wingfoil 0.2.1
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/LICENSE +21 -0
- package/README.md +334 -0
- package/dist/cli/error.d.ts +11 -0
- package/dist/cli/error.d.ts.map +1 -0
- package/dist/cli/error.js +27 -0
- package/dist/cli/error.js.map +1 -0
- package/dist/cli/exit.d.ts +19 -0
- package/dist/cli/exit.d.ts.map +1 -0
- package/dist/cli/exit.js +14 -0
- package/dist/cli/exit.js.map +1 -0
- package/dist/cli/index.d.ts +28 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +36 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init-command.d.ts +34 -0
- package/dist/cli/init-command.d.ts.map +1 -0
- package/dist/cli/init-command.js +100 -0
- package/dist/cli/init-command.js.map +1 -0
- package/dist/cli/mcp-command.d.ts +24 -0
- package/dist/cli/mcp-command.d.ts.map +1 -0
- package/dist/cli/mcp-command.js +42 -0
- package/dist/cli/mcp-command.js.map +1 -0
- package/dist/cli/output.d.ts +13 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +28 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/program.d.ts +12 -0
- package/dist/cli/program.d.ts.map +1 -0
- package/dist/cli/program.js +279 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/registrar.d.ts +69 -0
- package/dist/cli/registrar.d.ts.map +1 -0
- package/dist/cli/registrar.js +82 -0
- package/dist/cli/registrar.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +45 -0
- package/dist/cli.js.map +1 -0
- package/dist/core/approval-authority.d.ts +83 -0
- package/dist/core/approval-authority.d.ts.map +1 -0
- package/dist/core/approval-authority.js +112 -0
- package/dist/core/approval-authority.js.map +1 -0
- package/dist/core/builtin-asset.d.ts +71 -0
- package/dist/core/builtin-asset.d.ts.map +1 -0
- package/dist/core/builtin-asset.js +137 -0
- package/dist/core/builtin-asset.js.map +1 -0
- package/dist/core/builtin-integrity.d.ts +32 -0
- package/dist/core/builtin-integrity.d.ts.map +1 -0
- package/dist/core/builtin-integrity.js +148 -0
- package/dist/core/builtin-integrity.js.map +1 -0
- package/dist/core/confinement.d.ts +57 -0
- package/dist/core/confinement.d.ts.map +1 -0
- package/dist/core/confinement.js +108 -0
- package/dist/core/confinement.js.map +1 -0
- package/dist/core/context.d.ts +187 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +192 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/directive-assign.d.ts +131 -0
- package/dist/core/directive-assign.d.ts.map +1 -0
- package/dist/core/directive-assign.js +352 -0
- package/dist/core/directive-assign.js.map +1 -0
- package/dist/core/directives-list.d.ts +80 -0
- package/dist/core/directives-list.d.ts.map +1 -0
- package/dist/core/directives-list.js +148 -0
- package/dist/core/directives-list.js.map +1 -0
- package/dist/core/exit-code.d.ts +85 -0
- package/dist/core/exit-code.d.ts.map +1 -0
- package/dist/core/exit-code.js +163 -0
- package/dist/core/exit-code.js.map +1 -0
- package/dist/core/git-identity.d.ts +32 -0
- package/dist/core/git-identity.d.ts.map +1 -0
- package/dist/core/git-identity.js +72 -0
- package/dist/core/git-identity.js.map +1 -0
- package/dist/core/index.d.ts +388 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +1331 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/init.d.ts +78 -0
- package/dist/core/init.d.ts.map +1 -0
- package/dist/core/init.js +167 -0
- package/dist/core/init.js.map +1 -0
- package/dist/core/loaders.d.ts +174 -0
- package/dist/core/loaders.d.ts.map +1 -0
- package/dist/core/loaders.js +364 -0
- package/dist/core/loaders.js.map +1 -0
- package/dist/core/memory-add-type.d.ts +43 -0
- package/dist/core/memory-add-type.d.ts.map +1 -0
- package/dist/core/memory-add-type.js +151 -0
- package/dist/core/memory-add-type.js.map +1 -0
- package/dist/core/memory-transition.d.ts +111 -0
- package/dist/core/memory-transition.d.ts.map +1 -0
- package/dist/core/memory-transition.js +269 -0
- package/dist/core/memory-transition.js.map +1 -0
- package/dist/core/registry.d.ts +189 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +66 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/relevance.d.ts +86 -0
- package/dist/core/relevance.d.ts.map +1 -0
- package/dist/core/relevance.js +258 -0
- package/dist/core/relevance.js.map +1 -0
- package/dist/core/require-reason.d.ts +27 -0
- package/dist/core/require-reason.d.ts.map +1 -0
- package/dist/core/require-reason.js +95 -0
- package/dist/core/require-reason.js.map +1 -0
- package/dist/core/types.d.ts +45 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +22 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/usage-error.d.ts +20 -0
- package/dist/core/usage-error.d.ts.map +1 -0
- package/dist/core/usage-error.js +29 -0
- package/dist/core/usage-error.js.map +1 -0
- package/dist/core/write-guard.d.ts +99 -0
- package/dist/core/write-guard.d.ts.map +1 -0
- package/dist/core/write-guard.js +247 -0
- package/dist/core/write-guard.js.map +1 -0
- package/dist/directives/create.d.ts +47 -0
- package/dist/directives/create.d.ts.map +1 -0
- package/dist/directives/create.js +82 -0
- package/dist/directives/create.js.map +1 -0
- package/dist/directives/index.d.ts +20 -0
- package/dist/directives/index.d.ts.map +1 -0
- package/dist/directives/index.js +32 -0
- package/dist/directives/index.js.map +1 -0
- package/dist/directives/roles-edit.d.ts +53 -0
- package/dist/directives/roles-edit.d.ts.map +1 -0
- package/dist/directives/roles-edit.js +286 -0
- package/dist/directives/roles-edit.js.map +1 -0
- package/dist/directives/schema.d.ts +65 -0
- package/dist/directives/schema.d.ts.map +1 -0
- package/dist/directives/schema.js +68 -0
- package/dist/directives/schema.js.map +1 -0
- package/dist/dna/edit.d.ts +61 -0
- package/dist/dna/edit.d.ts.map +1 -0
- package/dist/dna/edit.js +429 -0
- package/dist/dna/edit.js.map +1 -0
- package/dist/dna/index.d.ts +24 -0
- package/dist/dna/index.d.ts.map +1 -0
- package/dist/dna/index.js +59 -0
- package/dist/dna/index.js.map +1 -0
- package/dist/dna/mutate.d.ts +74 -0
- package/dist/dna/mutate.d.ts.map +1 -0
- package/dist/dna/mutate.js +318 -0
- package/dist/dna/mutate.js.map +1 -0
- package/dist/dna/path.d.ts +175 -0
- package/dist/dna/path.d.ts.map +1 -0
- package/dist/dna/path.js +289 -0
- package/dist/dna/path.js.map +1 -0
- package/dist/dna/roles.d.ts +57 -0
- package/dist/dna/roles.d.ts.map +1 -0
- package/dist/dna/roles.js +50 -0
- package/dist/dna/roles.js.map +1 -0
- package/dist/dna/schema.d.ts +172 -0
- package/dist/dna/schema.d.ts.map +1 -0
- package/dist/dna/schema.js +182 -0
- package/dist/dna/schema.js.map +1 -0
- package/dist/dna/set.d.ts +145 -0
- package/dist/dna/set.d.ts.map +1 -0
- package/dist/dna/set.js +428 -0
- package/dist/dna/set.js.map +1 -0
- package/dist/mcp/dna-resource.d.ts +16 -0
- package/dist/mcp/dna-resource.d.ts.map +1 -0
- package/dist/mcp/dna-resource.js +56 -0
- package/dist/mcp/dna-resource.js.map +1 -0
- package/dist/mcp/index.d.ts +49 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +60 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/memory-resource.d.ts +17 -0
- package/dist/mcp/memory-resource.d.ts.map +1 -0
- package/dist/mcp/memory-resource.js +133 -0
- package/dist/mcp/memory-resource.js.map +1 -0
- package/dist/mcp/prompt.d.ts +48 -0
- package/dist/mcp/prompt.d.ts.map +1 -0
- package/dist/mcp/prompt.js +176 -0
- package/dist/mcp/prompt.js.map +1 -0
- package/dist/mcp/read-only.d.ts +42 -0
- package/dist/mcp/read-only.d.ts.map +1 -0
- package/dist/mcp/read-only.js +93 -0
- package/dist/mcp/read-only.js.map +1 -0
- package/dist/mcp/registrar.d.ts +54 -0
- package/dist/mcp/registrar.d.ts.map +1 -0
- package/dist/mcp/registrar.js +72 -0
- package/dist/mcp/registrar.js.map +1 -0
- package/dist/mcp/server.d.ts +58 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +64 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/workflow-resource.d.ts +17 -0
- package/dist/mcp/workflow-resource.d.ts.map +1 -0
- package/dist/mcp/workflow-resource.js +63 -0
- package/dist/mcp/workflow-resource.js.map +1 -0
- package/dist/memory/add.d.ts +50 -0
- package/dist/memory/add.d.ts.map +1 -0
- package/dist/memory/add.js +131 -0
- package/dist/memory/add.js.map +1 -0
- package/dist/memory/audit.d.ts +177 -0
- package/dist/memory/audit.d.ts.map +1 -0
- package/dist/memory/audit.js +287 -0
- package/dist/memory/audit.js.map +1 -0
- package/dist/memory/commit-message.d.ts +146 -0
- package/dist/memory/commit-message.d.ts.map +1 -0
- package/dist/memory/commit-message.js +203 -0
- package/dist/memory/commit-message.js.map +1 -0
- package/dist/memory/entry.d.ts +56 -0
- package/dist/memory/entry.d.ts.map +1 -0
- package/dist/memory/entry.js +28 -0
- package/dist/memory/entry.js.map +1 -0
- package/dist/memory/frontmatter-edit.d.ts +68 -0
- package/dist/memory/frontmatter-edit.d.ts.map +1 -0
- package/dist/memory/frontmatter-edit.js +333 -0
- package/dist/memory/frontmatter-edit.js.map +1 -0
- package/dist/memory/git-log.d.ts +32 -0
- package/dist/memory/git-log.d.ts.map +1 -0
- package/dist/memory/git-log.js +100 -0
- package/dist/memory/git-log.js.map +1 -0
- package/dist/memory/history.d.ts +142 -0
- package/dist/memory/history.d.ts.map +1 -0
- package/dist/memory/history.js +250 -0
- package/dist/memory/history.js.map +1 -0
- package/dist/memory/index.d.ts +58 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +107 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/query.d.ts +150 -0
- package/dist/memory/query.d.ts.map +1 -0
- package/dist/memory/query.js +307 -0
- package/dist/memory/query.js.map +1 -0
- package/dist/memory/reject.d.ts +11 -0
- package/dist/memory/reject.d.ts.map +1 -0
- package/dist/memory/reject.js +32 -0
- package/dist/memory/reject.js.map +1 -0
- package/dist/memory/schema.d.ts +104 -0
- package/dist/memory/schema.d.ts.map +1 -0
- package/dist/memory/schema.js +161 -0
- package/dist/memory/schema.js.map +1 -0
- package/dist/memory/state-machine.d.ts +166 -0
- package/dist/memory/state-machine.d.ts.map +1 -0
- package/dist/memory/state-machine.js +431 -0
- package/dist/memory/state-machine.js.map +1 -0
- package/dist/memory/submit.d.ts +11 -0
- package/dist/memory/submit.d.ts.map +1 -0
- package/dist/memory/submit.js +44 -0
- package/dist/memory/submit.js.map +1 -0
- package/dist/storage/builtin-directives.d.ts +54 -0
- package/dist/storage/builtin-directives.d.ts.map +1 -0
- package/dist/storage/builtin-directives.js +152 -0
- package/dist/storage/builtin-directives.js.map +1 -0
- package/dist/storage/commit.d.ts +92 -0
- package/dist/storage/commit.d.ts.map +1 -0
- package/dist/storage/commit.js +201 -0
- package/dist/storage/commit.js.map +1 -0
- package/dist/storage/confinement.d.ts +93 -0
- package/dist/storage/confinement.d.ts.map +1 -0
- package/dist/storage/confinement.js +164 -0
- package/dist/storage/confinement.js.map +1 -0
- package/dist/storage/document.d.ts +27 -0
- package/dist/storage/document.d.ts.map +1 -0
- package/dist/storage/document.js +52 -0
- package/dist/storage/document.js.map +1 -0
- package/dist/storage/errors.d.ts +36 -0
- package/dist/storage/errors.d.ts.map +1 -0
- package/dist/storage/errors.js +46 -0
- package/dist/storage/errors.js.map +1 -0
- package/dist/storage/frontmatter.d.ts +27 -0
- package/dist/storage/frontmatter.d.ts.map +1 -0
- package/dist/storage/frontmatter.js +37 -0
- package/dist/storage/frontmatter.js.map +1 -0
- package/dist/storage/git-root.d.ts +17 -0
- package/dist/storage/git-root.d.ts.map +1 -0
- package/dist/storage/git-root.js +49 -0
- package/dist/storage/git-root.js.map +1 -0
- package/dist/storage/index.d.ts +29 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +66 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/init-state.d.ts +9 -0
- package/dist/storage/init-state.d.ts.map +1 -0
- package/dist/storage/init-state.js +24 -0
- package/dist/storage/init-state.js.map +1 -0
- package/dist/storage/layout.d.ts +51 -0
- package/dist/storage/layout.d.ts.map +1 -0
- package/dist/storage/layout.js +88 -0
- package/dist/storage/layout.js.map +1 -0
- package/dist/storage/memory-path.d.ts +72 -0
- package/dist/storage/memory-path.d.ts.map +1 -0
- package/dist/storage/memory-path.js +127 -0
- package/dist/storage/memory-path.js.map +1 -0
- package/dist/storage/snapshot.d.ts +16 -0
- package/dist/storage/snapshot.d.ts.map +1 -0
- package/dist/storage/snapshot.js +72 -0
- package/dist/storage/snapshot.js.map +1 -0
- package/dist/storage/templates.d.ts +88 -0
- package/dist/storage/templates.d.ts.map +1 -0
- package/dist/storage/templates.js +422 -0
- package/dist/storage/templates.js.map +1 -0
- package/dist/validation/error-mapper.d.ts +16 -0
- package/dist/validation/error-mapper.d.ts.map +1 -0
- package/dist/validation/error-mapper.js +18 -0
- package/dist/validation/error-mapper.js.map +1 -0
- package/dist/validation/errors.d.ts +69 -0
- package/dist/validation/errors.d.ts.map +1 -0
- package/dist/validation/errors.js +69 -0
- package/dist/validation/errors.js.map +1 -0
- package/dist/validation/id.d.ts +16 -0
- package/dist/validation/id.d.ts.map +1 -0
- package/dist/validation/id.js +177 -0
- package/dist/validation/id.js.map +1 -0
- package/dist/validation/index.d.ts +18 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +37 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/secret-scan.d.ts +129 -0
- package/dist/validation/secret-scan.d.ts.map +1 -0
- package/dist/validation/secret-scan.js +367 -0
- package/dist/validation/secret-scan.js.map +1 -0
- package/dist/validation/two-pass.d.ts +24 -0
- package/dist/validation/two-pass.d.ts.map +1 -0
- package/dist/validation/two-pass.js +24 -0
- package/dist/validation/two-pass.js.map +1 -0
- package/dist/validation/warning.d.ts +31 -0
- package/dist/validation/warning.d.ts.map +1 -0
- package/dist/validation/warning.js +81 -0
- package/dist/validation/warning.js.map +1 -0
- package/dist/validation/yaml.d.ts +9 -0
- package/dist/validation/yaml.d.ts.map +1 -0
- package/dist/validation/yaml.js +30 -0
- package/dist/validation/yaml.js.map +1 -0
- package/dist/workflow/index.d.ts +10 -0
- package/dist/workflow/index.d.ts.map +1 -0
- package/dist/workflow/index.js +16 -0
- package/dist/workflow/index.js.map +1 -0
- package/dist/workflow/schema.d.ts +89 -0
- package/dist/workflow/schema.d.ts.map +1 -0
- package/dist/workflow/schema.js +73 -0
- package/dist/workflow/schema.js.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/memory/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import type { MemoryYaml, StateMachine } from './schema';
|
|
2
|
+
/** The reserved implicit-wildcard target state (spec-001) — never declared explicitly anywhere. */
|
|
3
|
+
export declare const DEPRECATED_STATE = "deprecated";
|
|
4
|
+
/**
|
|
5
|
+
* The terminal state of the `adr` and `tech-spec` machines (`memory.yaml`): reached along the forward
|
|
6
|
+
* `sequence` by `approve`, never by `memory deprecate`. A superseded decision is archived content — a
|
|
7
|
+
* later element explicitly replaced it — which is why `dl-028-archived-states-excluded-from-context`
|
|
8
|
+
* puts it in {@link ARCHIVED_STATUSES} alongside {@link DEPRECATED_STATE}.
|
|
9
|
+
*/
|
|
10
|
+
export declare const SUPERSEDED_STATE = "superseded";
|
|
11
|
+
/**
|
|
12
|
+
* The canonical **archived** status set, ratified by `dl-028-archived-states-excluded-from-context`:
|
|
13
|
+
* exactly `{deprecated, superseded}`, in this fixed order (REQ-SYS-07 — no unordered iteration in any
|
|
14
|
+
* output-affecting path).
|
|
15
|
+
*
|
|
16
|
+
* REQ-STATE-06's Rationale ("distinguish active from archived decisions") always named the archived
|
|
17
|
+
* set, but its Description and Fit Criterion named only `deprecated`; dl-028 closes that gap and the
|
|
18
|
+
* SARD entry now names both. The previously-specified `rejected` is **not** here: `spec-001-memory-yaml-schema`
|
|
19
|
+
* removed that status from every type's machine (a `reject` transition lands back on `draft`), so it
|
|
20
|
+
* can never appear in a document's frontmatter.
|
|
21
|
+
*/
|
|
22
|
+
export declare const ARCHIVED_STATUSES: readonly string[];
|
|
23
|
+
/**
|
|
24
|
+
* True when a document's frontmatter `status` is an archived state ({@link ARCHIVED_STATUSES}).
|
|
25
|
+
*
|
|
26
|
+
* This is the **single shared predicate** dl-028 mandates: both the default-search path
|
|
27
|
+
* (`searchMemoryDocuments`, REQ-STATE-06) and the agent-context path (`src/core/relevance.ts`'s
|
|
28
|
+
* relevance filter, spec-012 §6) consume it, so "archived" has exactly one definition. It supersedes
|
|
29
|
+
* `task-038`'s `isDeprecatedStatus`.
|
|
30
|
+
*
|
|
31
|
+
* It takes the **already-parsed status string**, not the raw frontmatter record: every call site
|
|
32
|
+
* projects `status` out of frontmatter anyway (for its own result shape), and a frontmatter-shaped
|
|
33
|
+
* predicate forced those callers either to re-parse or to hand back a record they had already
|
|
34
|
+
* destructured — the composition problem `task-038`'s reviewer flagged. Non-string / absent `status`
|
|
35
|
+
* values are normalised to `undefined` by the caller's own frontmatter projection and are never
|
|
36
|
+
* archived.
|
|
37
|
+
*
|
|
38
|
+
* Note the deliberate asymmetry with the *context* filter: `src/core/relevance.ts` excludes
|
|
39
|
+
* `draft` **in addition to** this archived set (spec-012 §6 — only "stable, decided and still-current"
|
|
40
|
+
* content enters an execution context), while default `memory search` keeps drafts visible.
|
|
41
|
+
* `draft` is therefore NOT part of the archived set.
|
|
42
|
+
*/
|
|
43
|
+
export declare function isArchivedStatus(status: string | undefined): boolean;
|
|
44
|
+
/** `E_INVALID_<X>` field-level code (spec-009 §3) for an illegal state transition. */
|
|
45
|
+
export declare const E_INVALID_TRANSITION = "E_INVALID_TRANSITION";
|
|
46
|
+
/**
|
|
47
|
+
* `E_INVALID_<X>` field-level code (spec-009 §3, spec-010-memory-frontmatter-schema "Validation
|
|
48
|
+
* rules") for a document frontmatter `status` value that is not a legal state for its declared type
|
|
49
|
+
* at all — as opposed to {@link E_INVALID_TRANSITION}, which flags an illegal *transition attempt*
|
|
50
|
+
* (verb + current state), not the current state's bare legality. See {@link validateFrontmatterState}.
|
|
51
|
+
*/
|
|
52
|
+
export declare const E_INVALID_STATE = "E_INVALID_STATE";
|
|
53
|
+
/** The four CLI verbs a transition can be requested for (`memory.add` assigns `sequence[0]` directly, no verb). */
|
|
54
|
+
export type TransitionOp = 'submit' | 'approve' | 'reject' | 'deprecate';
|
|
55
|
+
/**
|
|
56
|
+
* REQ-STATE-08's default machine, owned by the **engine** rather than by any config file
|
|
57
|
+
* (`bug-030-init-memory-yaml-has-no-state-machine`, task-071). It is the last arm of
|
|
58
|
+
* {@link resolveStateMachine}'s resolution: it governs every registered type that declares no `states`
|
|
59
|
+
* block in a `memory.yaml` that declares no `defaults.states` either.
|
|
60
|
+
*
|
|
61
|
+
* **Why the engine owns it.** REQ-STATE-08 states the rule over the *type* — "A Memory type that does
|
|
62
|
+
* not declare its own `states` uses the default machine" — with no mention of a `defaults` block, and
|
|
63
|
+
* its Rationale is "reduce config friction for simple types". `spec-001-memory-yaml-schema` makes
|
|
64
|
+
* `defaults` optional (`defaults: z.object({ states: StateMachine }).optional()`). A `memory.yaml`
|
|
65
|
+
* that omits `defaults` and registers a type without `states` is therefore a legal file whose types
|
|
66
|
+
* REQ-STATE-08 still gives a machine — which can only hold if the default exists without being
|
|
67
|
+
* declared. Before task-071 that combination threw instead, so every project `wingfoil init` created
|
|
68
|
+
* refused every transition verb (bug-030). BDD `p1-memory/P1.13-memory-element-schema.feature`
|
|
69
|
+
* scenario 2 is read the same way: its `Given` only puts a type in the file "without a `states`
|
|
70
|
+
* block", and its `Then` names the machine by value — so its title ("uses the defaults block")
|
|
71
|
+
* describes the common case rather than a precondition.
|
|
72
|
+
*
|
|
73
|
+
* **Why this value.** It is `spec-001`'s own worked `defaults` example, verbatim — not REQ-STATE-08's
|
|
74
|
+
* literal `draft → pending → approved/rejected → deprecated` wording, which `spec-001` §Consequences
|
|
75
|
+
* deliberately superseded: the default machine "loses its `rejected` state" ("no document ever records
|
|
76
|
+
* `status: rejected` again" — a `reject` from the `pending` gate lands straight back on `draft`), and
|
|
77
|
+
* `deprecated` is the reserved implicit wildcard reachable from any state, never declared in a
|
|
78
|
+
* `sequence` (the `StateMachine` schema's own `.superRefine()` forbids declaring it). The resulting
|
|
79
|
+
* legal set is exactly REQ-STATE-08's fit criterion under that encoding: `submit` draft→pending,
|
|
80
|
+
* `approve` pending→approved, `reject` pending→draft, `deprecate` →`deprecated` from anywhere, and
|
|
81
|
+
* nothing else.
|
|
82
|
+
*
|
|
83
|
+
* Frozen: it is shared by every type that falls back to it, so no consumer may mutate the machine
|
|
84
|
+
* other types are resolving (a shared constant, built once, with no per-call construction and no
|
|
85
|
+
* ordering dependence — REQ-SYS-07).
|
|
86
|
+
*/
|
|
87
|
+
export declare const DEFAULT_STATE_MACHINE: StateMachine;
|
|
88
|
+
/**
|
|
89
|
+
* Resolve the state machine that governs `typeName`, per REQ-STATE-08. Three arms, in precedence
|
|
90
|
+
* order — the first that exists wins:
|
|
91
|
+
*
|
|
92
|
+
* 1. the type's own `states` block (`types.<name>.states`);
|
|
93
|
+
* 2. the file's `defaults.states`, when it declares one — a per-project override of the built-in;
|
|
94
|
+
* 3. {@link DEFAULT_STATE_MACHINE}, the engine's built-in default (task-071 / bug-030).
|
|
95
|
+
*
|
|
96
|
+
* Because arm 3 always applies, **no registered type can fail to resolve a machine**: the previous
|
|
97
|
+
* "neither the type nor `defaults` declares a machine" throw is gone, and with it the failure that
|
|
98
|
+
* made every transition verb refuse in a freshly-`wingfoil init`-ed project.
|
|
99
|
+
*
|
|
100
|
+
* The one remaining throw is for a type that is **not registered at all**. It is a plain `Error`, not
|
|
101
|
+
* a `ValidationError`, because it is a caller-programming-error condition rather than a
|
|
102
|
+
* document-transition failure — and it is not reachable from any CLI or MCP call: every transition
|
|
103
|
+
* verb goes through `prepareMemoryTransition` (`src/core/memory-transition.ts`), which returns the
|
|
104
|
+
* `NOT_FOUND` result `unknown memory type '<t>' (not defined in memory.yaml)` (exit `1`) for an
|
|
105
|
+
* unregistered type *before* calling this function. Only a direct library call naming a type the file
|
|
106
|
+
* does not register can reach it.
|
|
107
|
+
*/
|
|
108
|
+
export declare function resolveStateMachine(memoryYaml: MemoryYaml, typeName: string): StateMachine;
|
|
109
|
+
/**
|
|
110
|
+
* Compute the legal target state for `op` applied to `currentState` under `machine`. Returns the
|
|
111
|
+
* target state on success; throws `ValidationError` (never returns a target) when the transition is
|
|
112
|
+
* illegal, per REQ-STATE-01 — a caller must never write a document's `status` unless this function
|
|
113
|
+
* returns normally. `filePath` is only used to enrich the thrown error's `file` field (optional —
|
|
114
|
+
* defaults to `''` when no document is on hand, e.g. in pure unit tests).
|
|
115
|
+
*/
|
|
116
|
+
export declare function resolveTransitionTarget(machine: StateMachine, currentState: string, op: TransitionOp, filePath?: string): string;
|
|
117
|
+
/**
|
|
118
|
+
* Resolve the legal target of verb `op` for a document of type `typeName` currently in `currentState`
|
|
119
|
+
* — the entry point every Memory transition verb (`submit`, and `approve`/`reject`/`deprecate` after
|
|
120
|
+
* it) uses. It resolves the type's machine ({@link resolveStateMachine}, REQ-STATE-08) and delegates
|
|
121
|
+
* legality to {@link resolveTransitionTarget}, adding only the user-facing contract:
|
|
122
|
+
*
|
|
123
|
+
* An illegal transition is rethrown as the `E_INVALID_TRANSITION` issue ratified by
|
|
124
|
+
* `dl-032-illegal-transition-message-contract` (option (c)) — `message` is the pinned
|
|
125
|
+
* `` illegal transition <from> -> <to> for type '<type>' `` (REQ-STATE-01 Fit Criterion; BDD `P1.6`
|
|
126
|
+
* sc.2, `P5.2.3` sc.2), `detail` carries the engine's explanation of *why* the edge is illegal, and the
|
|
127
|
+
* exit code is `1`. `<to>` is computed by {@link contractTarget}.
|
|
128
|
+
*
|
|
129
|
+
* @throws {@link ../validation.ValidationError} `E_INVALID_TRANSITION` (exit `1`) as above.
|
|
130
|
+
* @throws `Error` when `typeName` is not registered (see {@link resolveStateMachine}). A registered type
|
|
131
|
+
* can no longer fail to resolve a machine: REQ-STATE-08's built-in default is the last fallback.
|
|
132
|
+
*/
|
|
133
|
+
export declare function resolveTypeTransition(memoryYaml: MemoryYaml, typeName: string, currentState: string, op: TransitionOp, filePath?: string): string;
|
|
134
|
+
/**
|
|
135
|
+
* Assert that `status` — a value read straight off a document's frontmatter — is a legal state for
|
|
136
|
+
* `typeName` under `machine` (REQ-STATE-01: state is derived from frontmatter; spec-010's "Validation
|
|
137
|
+
* rules": *"`status` must be a value in the type's `states.values`"*). The legal set is exactly
|
|
138
|
+
* {@link isDeclaredState}'s: `sequence` ∪ every `gates.<state>.reject` target ∪ `deprecated`.
|
|
139
|
+
*
|
|
140
|
+
* This is a distinct check from {@link resolveTransitionTarget}: that function asks "is verb `op`
|
|
141
|
+
* legal FROM `currentState`", assuming `currentState` is already known-legal; this function asks
|
|
142
|
+
* whether an arbitrary `status` string is itself a legal state for the type at all — independent of
|
|
143
|
+
* any transition attempt, e.g. when validating a document's frontmatter as read (BDD
|
|
144
|
+
* `P4.11-deliverables.feature` scenario 3, `P4.13-state-deduction.feature` scenario 3). The two must
|
|
145
|
+
* agree: any state `resolveTransitionTarget` can return must validate here, or the tool would refuse
|
|
146
|
+
* a document it wrote itself.
|
|
147
|
+
*
|
|
148
|
+
* @throws {@link ../validation.ValidationError} `E_INVALID_STATE` with the message
|
|
149
|
+
* `` invalid state '<status>' for type '<typeName>' `` when `status` is not a legal state for
|
|
150
|
+
* `typeName`. **Exit code `1`**, per spec-009-validation-strategy §3 as rewritten under
|
|
151
|
+
* `dl-032-illegal-transition-message-contract`: the code keys on the *nature* of the failure, not
|
|
152
|
+
* the pass that detected it — `2` is reserved for parse and system-integrity failures, while "every
|
|
153
|
+
* other validation failure ... including business-rule failures detected in Pass 2" exits `1`. An
|
|
154
|
+
* unrecognised `status` is understood input that a rule refused, so it is a `1`; that is why this
|
|
155
|
+
* throws the `ValidationError` constructor directly rather than `ValidationError.semantic(...)`,
|
|
156
|
+
* which hard-codes `2` for the genuine integrity checks (`loaders`, `id`, `query`). No BDD scenario
|
|
157
|
+
* pins an exit code for this message — `P4.11` sc.3 and `P4.13` sc.3 pin the text only — so the spec
|
|
158
|
+
* rule governs unopposed. (The separate `E_INVALID_TRANSITION` message/exit-code realignment that
|
|
159
|
+
* `dl-032` ratified lives in {@link resolveTypeTransition}, added by `task-045-memory-submit`.)
|
|
160
|
+
*
|
|
161
|
+
* `filePath` is only used to enrich the thrown error's `file` field (optional — defaults to `''`
|
|
162
|
+
* when no document is on hand, e.g. in pure unit tests), mirroring {@link resolveTransitionTarget}'s
|
|
163
|
+
* own `filePath` parameter.
|
|
164
|
+
*/
|
|
165
|
+
export declare function validateFrontmatterState(machine: StateMachine, typeName: string, status: string, filePath?: string): void;
|
|
166
|
+
//# sourceMappingURL=state-machine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-machine.d.ts","sourceRoot":"","sources":["../../src/memory/state-machine.ts"],"names":[],"mappings":"AAuEA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAEzD,mGAAmG;AACnG,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAE7C;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,eAAe,CAAC;AAE7C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,MAAM,EAAwD,CAAC;AAExG;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEpE;AAED,sFAAsF;AACtF,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAE3D;;;;;GAKG;AACH,eAAO,MAAM,eAAe,oBAAoB,CAAC;AAEjD,mHAAmH;AACnH,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;AAEzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,qBAAqB,EAAE,YAahC,CAAC;AAEL;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAM1F;AAmBD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,YAAY,EACrB,YAAY,EAAE,MAAM,EACpB,EAAE,EAAE,YAAY,EAChB,QAAQ,SAAK,GACZ,MAAM,CA8DR;AAsCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,UAAU,EACtB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,EAAE,EAAE,YAAY,EAChB,QAAQ,SAAK,GACZ,MAAM,CAiBR;AAuCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,QAAQ,SAAK,GACZ,IAAI,CAYN"}
|
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_STATE_MACHINE = exports.E_INVALID_STATE = exports.E_INVALID_TRANSITION = exports.ARCHIVED_STATUSES = exports.SUPERSEDED_STATE = exports.DEPRECATED_STATE = void 0;
|
|
4
|
+
exports.isArchivedStatus = isArchivedStatus;
|
|
5
|
+
exports.resolveStateMachine = resolveStateMachine;
|
|
6
|
+
exports.resolveTransitionTarget = resolveTransitionTarget;
|
|
7
|
+
exports.resolveTypeTransition = resolveTypeTransition;
|
|
8
|
+
exports.validateFrontmatterState = validateFrontmatterState;
|
|
9
|
+
/**
|
|
10
|
+
* State-machine transition-legality engine (REQ-SYS-04, task-005-per-type-state-machines).
|
|
11
|
+
*
|
|
12
|
+
* task-004-decoupled-pillars already shipped the *structural* `StateMachine` Zod schema in
|
|
13
|
+
* `./schema.ts` — the `sequence`/`gates`/`waiting` shape plus a `.superRefine()` enforcing
|
|
14
|
+
* spec-001-memory-yaml-schema's "Semantic validation (post-parse)" rules (gates/waiting keys must be
|
|
15
|
+
* members of `sequence`, `"deprecated"` is reserved, etc.). This module does NOT re-validate any of
|
|
16
|
+
* that — it takes an already-parsed, already-structurally-valid `StateMachine` and answers a
|
|
17
|
+
* different question: **given a document's current `status` and a requested CLI verb
|
|
18
|
+
* (`submit`/`approve`/`reject`/`deprecate`), what is the legal target state, if any?**
|
|
19
|
+
*
|
|
20
|
+
* This is spec-009-validation-strategy §1's Pass 2 (semantic / cross-file): the transition rule
|
|
21
|
+
* needs the type's registered machine (loaded from `memory.yaml`) plus the document's own `status`
|
|
22
|
+
* field — neither is decidable from the document's frontmatter schema alone, matching spec-009's own
|
|
23
|
+
* worked example ("`wingfoil.status` must be a member of that type's `states.values`"). An illegal
|
|
24
|
+
* transition throws the shared `ValidationError` (exit code `1` — a business-rule failure, not an
|
|
25
|
+
* integrity one, per spec-009 §3 as rewritten under `dl-032-illegal-transition-message-contract`)
|
|
26
|
+
* and — critically — throws *before* returning any target, so a caller can never reach
|
|
27
|
+
* the frontmatter-write step on an illegal transition (REQ-STATE-01: rejected before any file write).
|
|
28
|
+
* This module never touches a document or the filesystem itself; it is a pure function of
|
|
29
|
+
* (`machine`, `currentState`, `op`) → target-or-throw, and it is the caller's job to gate any actual
|
|
30
|
+
* write on this function returning normally.
|
|
31
|
+
*
|
|
32
|
+
* Rules implemented below (spec-001-memory-yaml-schema, "Sub-schema: StateMachine" +
|
|
33
|
+
* "Which verb drives each forward edge — fully determined by the schema" + "`deprecated` is
|
|
34
|
+
* implicit"):
|
|
35
|
+
*
|
|
36
|
+
* - `submit`: legal only from a state that is in `sequence`, is NOT a `gates` key, and is NOT in
|
|
37
|
+
* `waiting`, and that has a next state in `sequence`. Target: the next state in `sequence`.
|
|
38
|
+
* - `approve`: legal only from a state that IS a `gates` key and is NOT also in `waiting` (a state
|
|
39
|
+
* that is both is spec-001's explicit "verb-less" case: "its forward edge is verb-less (picked up
|
|
40
|
+
* automatically)" — the manual `approve` verb does not apply, only the manual `reject` does).
|
|
41
|
+
* Target: the next state in `sequence`.
|
|
42
|
+
* - `reject`: legal only from a state that IS a `gates` key (regardless of `waiting` membership —
|
|
43
|
+
* spec-001: a gate+waiting state "still exposes a manual `reject`/decline path"). Target:
|
|
44
|
+
* `gates[<state>].reject`, always taken verbatim (it need not be a `sequence` member).
|
|
45
|
+
* - `deprecate`: the implicit wildcard edge — always legal from any current state, target is the
|
|
46
|
+
* reserved `"deprecated"` state. Never declared in `sequence`/`gates`/`waiting` (enforced
|
|
47
|
+
* structurally by task-004's `.superRefine()`; this engine does not need to re-check it).
|
|
48
|
+
* - Anything else (state not a member of `sequence` at all, wrong verb for the state's category, or
|
|
49
|
+
* a `sequence`-terminal state with no next entry) is illegal.
|
|
50
|
+
*
|
|
51
|
+
* task-036-frontmatter-lifecycle-validation adds {@link validateFrontmatterState} — a distinct check
|
|
52
|
+
* from the transition engine above: REQ-STATE-01's "document state derived from frontmatter" half,
|
|
53
|
+
* independent of any transition attempt. `resolveTransitionTarget` only answers "is verb `op` legal
|
|
54
|
+
* FROM `currentState`"; it never asserts that an arbitrary `status` string read off a document's
|
|
55
|
+
* frontmatter is itself a member of the type's declared state set at all — the check
|
|
56
|
+
* spec-010-memory-frontmatter-schema's "Validation rules" table names ("`status` must be a value in
|
|
57
|
+
* the type's `states.values`" → failure "invalid state for type") and BDD
|
|
58
|
+
* `P4.11-deliverables.feature`/`P4.13-state-deduction.feature` both exercise (`"invalid state
|
|
59
|
+
* 'shipped' for type 'task'"`). A state is legal for a type iff it belongs to that machine's full
|
|
60
|
+
* reachable set — `sequence` ∪ every `gates.<state>.reject` target (spec-001 permits those to be
|
|
61
|
+
* off-chain, and `resolveTransitionTarget` returns them verbatim) ∪ the reserved implicit
|
|
62
|
+
* `"deprecated"` state (never declared in `sequence` itself, per the `StateMachine` schema's own
|
|
63
|
+
* `.superRefine()`, but always a legal transition target via `memory.deprecate` — see
|
|
64
|
+
* `resolveTransitionTarget`'s `deprecate` case above).
|
|
65
|
+
*
|
|
66
|
+
* **Type resolution (REQ-STATE-08):** `resolveStateMachine` resolves a type's machine as
|
|
67
|
+
* `types.<name>.states ?? defaults.states ?? `{@link DEFAULT_STATE_MACHINE}. task-005's own tests
|
|
68
|
+
* exercise only the real types registered in `docs/self/.wingfoil/memory.yaml`, every one of which
|
|
69
|
+
* declares its own `states` block — so the `?? defaults.states` arm was left uncovered by that task,
|
|
70
|
+
* and `task-010-default-state-machine-fallback` closed that gap with a throwaway fixture type
|
|
71
|
+
* (declared with no `states:` key) in `test/memory/state-machine.test.ts`. The **third** arm is
|
|
72
|
+
* task-071's (`bug-030-init-memory-yaml-has-no-state-machine`): task-010's fixture still *declared* a
|
|
73
|
+
* `defaults` block, so a file with no machine anywhere — the shape `wingfoil init` scaffolded — was
|
|
74
|
+
* never resolved by anything, and it threw. See {@link DEFAULT_STATE_MACHINE} for why the engine, not
|
|
75
|
+
* the config file, owns that default.
|
|
76
|
+
*/
|
|
77
|
+
const validation_1 = require("../validation");
|
|
78
|
+
const schema_1 = require("./schema");
|
|
79
|
+
/** The reserved implicit-wildcard target state (spec-001) — never declared explicitly anywhere. */
|
|
80
|
+
exports.DEPRECATED_STATE = 'deprecated';
|
|
81
|
+
/**
|
|
82
|
+
* The terminal state of the `adr` and `tech-spec` machines (`memory.yaml`): reached along the forward
|
|
83
|
+
* `sequence` by `approve`, never by `memory deprecate`. A superseded decision is archived content — a
|
|
84
|
+
* later element explicitly replaced it — which is why `dl-028-archived-states-excluded-from-context`
|
|
85
|
+
* puts it in {@link ARCHIVED_STATUSES} alongside {@link DEPRECATED_STATE}.
|
|
86
|
+
*/
|
|
87
|
+
exports.SUPERSEDED_STATE = 'superseded';
|
|
88
|
+
/**
|
|
89
|
+
* The canonical **archived** status set, ratified by `dl-028-archived-states-excluded-from-context`:
|
|
90
|
+
* exactly `{deprecated, superseded}`, in this fixed order (REQ-SYS-07 — no unordered iteration in any
|
|
91
|
+
* output-affecting path).
|
|
92
|
+
*
|
|
93
|
+
* REQ-STATE-06's Rationale ("distinguish active from archived decisions") always named the archived
|
|
94
|
+
* set, but its Description and Fit Criterion named only `deprecated`; dl-028 closes that gap and the
|
|
95
|
+
* SARD entry now names both. The previously-specified `rejected` is **not** here: `spec-001-memory-yaml-schema`
|
|
96
|
+
* removed that status from every type's machine (a `reject` transition lands back on `draft`), so it
|
|
97
|
+
* can never appear in a document's frontmatter.
|
|
98
|
+
*/
|
|
99
|
+
exports.ARCHIVED_STATUSES = Object.freeze([exports.DEPRECATED_STATE, exports.SUPERSEDED_STATE]);
|
|
100
|
+
/**
|
|
101
|
+
* True when a document's frontmatter `status` is an archived state ({@link ARCHIVED_STATUSES}).
|
|
102
|
+
*
|
|
103
|
+
* This is the **single shared predicate** dl-028 mandates: both the default-search path
|
|
104
|
+
* (`searchMemoryDocuments`, REQ-STATE-06) and the agent-context path (`src/core/relevance.ts`'s
|
|
105
|
+
* relevance filter, spec-012 §6) consume it, so "archived" has exactly one definition. It supersedes
|
|
106
|
+
* `task-038`'s `isDeprecatedStatus`.
|
|
107
|
+
*
|
|
108
|
+
* It takes the **already-parsed status string**, not the raw frontmatter record: every call site
|
|
109
|
+
* projects `status` out of frontmatter anyway (for its own result shape), and a frontmatter-shaped
|
|
110
|
+
* predicate forced those callers either to re-parse or to hand back a record they had already
|
|
111
|
+
* destructured — the composition problem `task-038`'s reviewer flagged. Non-string / absent `status`
|
|
112
|
+
* values are normalised to `undefined` by the caller's own frontmatter projection and are never
|
|
113
|
+
* archived.
|
|
114
|
+
*
|
|
115
|
+
* Note the deliberate asymmetry with the *context* filter: `src/core/relevance.ts` excludes
|
|
116
|
+
* `draft` **in addition to** this archived set (spec-012 §6 — only "stable, decided and still-current"
|
|
117
|
+
* content enters an execution context), while default `memory search` keeps drafts visible.
|
|
118
|
+
* `draft` is therefore NOT part of the archived set.
|
|
119
|
+
*/
|
|
120
|
+
function isArchivedStatus(status) {
|
|
121
|
+
return status !== undefined && exports.ARCHIVED_STATUSES.includes(status);
|
|
122
|
+
}
|
|
123
|
+
/** `E_INVALID_<X>` field-level code (spec-009 §3) for an illegal state transition. */
|
|
124
|
+
exports.E_INVALID_TRANSITION = 'E_INVALID_TRANSITION';
|
|
125
|
+
/**
|
|
126
|
+
* `E_INVALID_<X>` field-level code (spec-009 §3, spec-010-memory-frontmatter-schema "Validation
|
|
127
|
+
* rules") for a document frontmatter `status` value that is not a legal state for its declared type
|
|
128
|
+
* at all — as opposed to {@link E_INVALID_TRANSITION}, which flags an illegal *transition attempt*
|
|
129
|
+
* (verb + current state), not the current state's bare legality. See {@link validateFrontmatterState}.
|
|
130
|
+
*/
|
|
131
|
+
exports.E_INVALID_STATE = 'E_INVALID_STATE';
|
|
132
|
+
/**
|
|
133
|
+
* REQ-STATE-08's default machine, owned by the **engine** rather than by any config file
|
|
134
|
+
* (`bug-030-init-memory-yaml-has-no-state-machine`, task-071). It is the last arm of
|
|
135
|
+
* {@link resolveStateMachine}'s resolution: it governs every registered type that declares no `states`
|
|
136
|
+
* block in a `memory.yaml` that declares no `defaults.states` either.
|
|
137
|
+
*
|
|
138
|
+
* **Why the engine owns it.** REQ-STATE-08 states the rule over the *type* — "A Memory type that does
|
|
139
|
+
* not declare its own `states` uses the default machine" — with no mention of a `defaults` block, and
|
|
140
|
+
* its Rationale is "reduce config friction for simple types". `spec-001-memory-yaml-schema` makes
|
|
141
|
+
* `defaults` optional (`defaults: z.object({ states: StateMachine }).optional()`). A `memory.yaml`
|
|
142
|
+
* that omits `defaults` and registers a type without `states` is therefore a legal file whose types
|
|
143
|
+
* REQ-STATE-08 still gives a machine — which can only hold if the default exists without being
|
|
144
|
+
* declared. Before task-071 that combination threw instead, so every project `wingfoil init` created
|
|
145
|
+
* refused every transition verb (bug-030). BDD `p1-memory/P1.13-memory-element-schema.feature`
|
|
146
|
+
* scenario 2 is read the same way: its `Given` only puts a type in the file "without a `states`
|
|
147
|
+
* block", and its `Then` names the machine by value — so its title ("uses the defaults block")
|
|
148
|
+
* describes the common case rather than a precondition.
|
|
149
|
+
*
|
|
150
|
+
* **Why this value.** It is `spec-001`'s own worked `defaults` example, verbatim — not REQ-STATE-08's
|
|
151
|
+
* literal `draft → pending → approved/rejected → deprecated` wording, which `spec-001` §Consequences
|
|
152
|
+
* deliberately superseded: the default machine "loses its `rejected` state" ("no document ever records
|
|
153
|
+
* `status: rejected` again" — a `reject` from the `pending` gate lands straight back on `draft`), and
|
|
154
|
+
* `deprecated` is the reserved implicit wildcard reachable from any state, never declared in a
|
|
155
|
+
* `sequence` (the `StateMachine` schema's own `.superRefine()` forbids declaring it). The resulting
|
|
156
|
+
* legal set is exactly REQ-STATE-08's fit criterion under that encoding: `submit` draft→pending,
|
|
157
|
+
* `approve` pending→approved, `reject` pending→draft, `deprecate` →`deprecated` from anywhere, and
|
|
158
|
+
* nothing else.
|
|
159
|
+
*
|
|
160
|
+
* Frozen: it is shared by every type that falls back to it, so no consumer may mutate the machine
|
|
161
|
+
* other types are resolving (a shared constant, built once, with no per-call construction and no
|
|
162
|
+
* ordering dependence — REQ-SYS-07).
|
|
163
|
+
*/
|
|
164
|
+
exports.DEFAULT_STATE_MACHINE = (() => {
|
|
165
|
+
// Built through the real `StateMachine` schema, so the built-in is held to exactly the structural
|
|
166
|
+
// rules (`gates` keys ⊆ `sequence`, `"deprecated"` never declared) every hand-written machine is —
|
|
167
|
+
// a malformed default would otherwise be the one machine nothing validates. Frozen through, so a
|
|
168
|
+
// consumer cannot mutate what every falling-back type resolves.
|
|
169
|
+
const machine = schema_1.StateMachine.parse({
|
|
170
|
+
sequence: ['draft', 'pending', 'approved'],
|
|
171
|
+
gates: { pending: { reject: 'draft' } },
|
|
172
|
+
});
|
|
173
|
+
Object.freeze(machine.sequence);
|
|
174
|
+
Object.freeze(machine.gates['pending']);
|
|
175
|
+
Object.freeze(machine.gates);
|
|
176
|
+
return Object.freeze(machine);
|
|
177
|
+
})();
|
|
178
|
+
/**
|
|
179
|
+
* Resolve the state machine that governs `typeName`, per REQ-STATE-08. Three arms, in precedence
|
|
180
|
+
* order — the first that exists wins:
|
|
181
|
+
*
|
|
182
|
+
* 1. the type's own `states` block (`types.<name>.states`);
|
|
183
|
+
* 2. the file's `defaults.states`, when it declares one — a per-project override of the built-in;
|
|
184
|
+
* 3. {@link DEFAULT_STATE_MACHINE}, the engine's built-in default (task-071 / bug-030).
|
|
185
|
+
*
|
|
186
|
+
* Because arm 3 always applies, **no registered type can fail to resolve a machine**: the previous
|
|
187
|
+
* "neither the type nor `defaults` declares a machine" throw is gone, and with it the failure that
|
|
188
|
+
* made every transition verb refuse in a freshly-`wingfoil init`-ed project.
|
|
189
|
+
*
|
|
190
|
+
* The one remaining throw is for a type that is **not registered at all**. It is a plain `Error`, not
|
|
191
|
+
* a `ValidationError`, because it is a caller-programming-error condition rather than a
|
|
192
|
+
* document-transition failure — and it is not reachable from any CLI or MCP call: every transition
|
|
193
|
+
* verb goes through `prepareMemoryTransition` (`src/core/memory-transition.ts`), which returns the
|
|
194
|
+
* `NOT_FOUND` result `unknown memory type '<t>' (not defined in memory.yaml)` (exit `1`) for an
|
|
195
|
+
* unregistered type *before* calling this function. Only a direct library call naming a type the file
|
|
196
|
+
* does not register can reach it.
|
|
197
|
+
*/
|
|
198
|
+
function resolveStateMachine(memoryYaml, typeName) {
|
|
199
|
+
const typeEntry = memoryYaml.types[typeName];
|
|
200
|
+
if (!typeEntry) {
|
|
201
|
+
throw new Error(`memory.yaml has no type "${typeName}" registered`);
|
|
202
|
+
}
|
|
203
|
+
return typeEntry.states ?? memoryYaml.defaults?.states ?? exports.DEFAULT_STATE_MACHINE;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Build one `E_INVALID_TRANSITION` `ValidationError` and throw it. Exits `1`: an illegal transition is
|
|
207
|
+
* understood input that a rule refused, not a parse/integrity failure (spec-009 §3, `dl-032`) — so the
|
|
208
|
+
* plain constructor, not `ValidationError.semantic(...)`. The message here is the type-agnostic
|
|
209
|
+
* diagnostic; {@link resolveTypeTransition} turns it into the pinned contract message.
|
|
210
|
+
*/
|
|
211
|
+
function illegal(currentState, op, message, filePath) {
|
|
212
|
+
throw new validation_1.ValidationError([
|
|
213
|
+
{
|
|
214
|
+
code: exports.E_INVALID_TRANSITION,
|
|
215
|
+
path: 'status',
|
|
216
|
+
file: filePath,
|
|
217
|
+
message: `illegal \`${op}\` from "${currentState}": ${message}`,
|
|
218
|
+
},
|
|
219
|
+
]);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Compute the legal target state for `op` applied to `currentState` under `machine`. Returns the
|
|
223
|
+
* target state on success; throws `ValidationError` (never returns a target) when the transition is
|
|
224
|
+
* illegal, per REQ-STATE-01 — a caller must never write a document's `status` unless this function
|
|
225
|
+
* returns normally. `filePath` is only used to enrich the thrown error's `file` field (optional —
|
|
226
|
+
* defaults to `''` when no document is on hand, e.g. in pure unit tests).
|
|
227
|
+
*/
|
|
228
|
+
function resolveTransitionTarget(machine, currentState, op, filePath = '') {
|
|
229
|
+
if (op === 'deprecate') {
|
|
230
|
+
// Implicit wildcard edge from any state (spec-001) — always legal, never declared explicitly.
|
|
231
|
+
return exports.DEPRECATED_STATE;
|
|
232
|
+
}
|
|
233
|
+
const index = machine.sequence.indexOf(currentState);
|
|
234
|
+
const gate = (machine.gates ?? {})[currentState];
|
|
235
|
+
const isWaiting = (machine.waiting ?? []).includes(currentState);
|
|
236
|
+
switch (op) {
|
|
237
|
+
case 'submit': {
|
|
238
|
+
if (index === -1) {
|
|
239
|
+
return illegal(currentState, op, "not a member of this type's `sequence`", filePath);
|
|
240
|
+
}
|
|
241
|
+
if (gate) {
|
|
242
|
+
return illegal(currentState, op, 'a `gates` state — its forward edge requires `approve`, not `submit`', filePath);
|
|
243
|
+
}
|
|
244
|
+
if (isWaiting) {
|
|
245
|
+
return illegal(currentState, op, 'a `waiting` state — its forward edge fires only via a Workflow action, not `submit`', filePath);
|
|
246
|
+
}
|
|
247
|
+
const next = machine.sequence[index + 1];
|
|
248
|
+
if (next === undefined) {
|
|
249
|
+
return illegal(currentState, op, 'the last state in `sequence` — there is no forward edge', filePath);
|
|
250
|
+
}
|
|
251
|
+
return next;
|
|
252
|
+
}
|
|
253
|
+
case 'approve': {
|
|
254
|
+
if (!gate) {
|
|
255
|
+
return illegal(currentState, op, 'not a `gates` state — `approve` is only legal from a gate', filePath);
|
|
256
|
+
}
|
|
257
|
+
if (isWaiting) {
|
|
258
|
+
return illegal(currentState, op, 'both a `gates` and `waiting` state — its forward edge is verb-less (fires only via a Workflow action), not `approve`', filePath);
|
|
259
|
+
}
|
|
260
|
+
const next = machine.sequence[index + 1];
|
|
261
|
+
if (next === undefined) {
|
|
262
|
+
return illegal(currentState, op, 'a `gates` state with no next `sequence` entry to approve into', filePath);
|
|
263
|
+
}
|
|
264
|
+
return next;
|
|
265
|
+
}
|
|
266
|
+
case 'reject': {
|
|
267
|
+
if (!gate) {
|
|
268
|
+
return illegal(currentState, op, 'not a `gates` state — `reject` is only legal from a gate', filePath);
|
|
269
|
+
}
|
|
270
|
+
// `reject` target is taken verbatim — need not be a `sequence` member (spec-001).
|
|
271
|
+
return gate.reject;
|
|
272
|
+
}
|
|
273
|
+
default: {
|
|
274
|
+
const exhaustive = op;
|
|
275
|
+
return illegal(currentState, exhaustive, 'unknown operation', filePath);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/** What the contract message prints for `<to>` when a verb has no legal edge anywhere in the machine. */
|
|
280
|
+
const NO_TARGET = '(none)';
|
|
281
|
+
/**
|
|
282
|
+
* The `<to>` of the illegal-transition contract message: the verb's **canonical edge** for this type —
|
|
283
|
+
* the target `op` reaches from the first state, in `sequence` order, from which `op` is legal (for
|
|
284
|
+
* `submit` on `task` or on the default machine: `pending`; on `release`: `planning`). A verb names no
|
|
285
|
+
* target of its own, so the message needs a rule; this one reproduces the string BDD `P1.6` sc.2 and
|
|
286
|
+
* `P5.2.3` sc.2 pin (`approved -> pending` for `task`) on both the default machine and the real `task`
|
|
287
|
+
* machine, where the literal forward edge out of `approved` is `done`.
|
|
288
|
+
*
|
|
289
|
+
* What happens when that canonical target IS `currentState` — printing it would be a self-loop — is
|
|
290
|
+
* ratified by `dl-053-illegal-transition-target-for-verbless-edges` (option 1): **keep walking
|
|
291
|
+
* `sequence` for the next legal edge of the SAME verb**, and render {@link NO_TARGET} when the verb
|
|
292
|
+
* has no other target. It must never name the next state in `sequence` regardless of verb — the
|
|
293
|
+
* earlier fallback did, printing `draft -> pending` for a `reject` (a rejection shown as a forward
|
|
294
|
+
* move) and `backlog -> in-progress` for an `approve` (a `waiting` edge no verb drives), misinforming
|
|
295
|
+
* exactly the user who has just made an illegal call. Every `<to>` printed here is therefore a real
|
|
296
|
+
* target of the verb the user typed, on this type's own machine.
|
|
297
|
+
*
|
|
298
|
+
* A pure function of `(machine, currentState, op)` walked in `sequence` order (REQ-SYS-07).
|
|
299
|
+
*/
|
|
300
|
+
function contractTarget(machine, currentState, op) {
|
|
301
|
+
for (const state of machine.sequence) {
|
|
302
|
+
let target;
|
|
303
|
+
try {
|
|
304
|
+
target = resolveTransitionTarget(machine, state, op);
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
continue; // `op` is not legal from this state — keep walking the chain
|
|
308
|
+
}
|
|
309
|
+
// dl-053: a self-loop is not a transition; keep looking for a different target of this same verb.
|
|
310
|
+
if (target !== currentState)
|
|
311
|
+
return target;
|
|
312
|
+
}
|
|
313
|
+
return NO_TARGET;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Resolve the legal target of verb `op` for a document of type `typeName` currently in `currentState`
|
|
317
|
+
* — the entry point every Memory transition verb (`submit`, and `approve`/`reject`/`deprecate` after
|
|
318
|
+
* it) uses. It resolves the type's machine ({@link resolveStateMachine}, REQ-STATE-08) and delegates
|
|
319
|
+
* legality to {@link resolveTransitionTarget}, adding only the user-facing contract:
|
|
320
|
+
*
|
|
321
|
+
* An illegal transition is rethrown as the `E_INVALID_TRANSITION` issue ratified by
|
|
322
|
+
* `dl-032-illegal-transition-message-contract` (option (c)) — `message` is the pinned
|
|
323
|
+
* `` illegal transition <from> -> <to> for type '<type>' `` (REQ-STATE-01 Fit Criterion; BDD `P1.6`
|
|
324
|
+
* sc.2, `P5.2.3` sc.2), `detail` carries the engine's explanation of *why* the edge is illegal, and the
|
|
325
|
+
* exit code is `1`. `<to>` is computed by {@link contractTarget}.
|
|
326
|
+
*
|
|
327
|
+
* @throws {@link ../validation.ValidationError} `E_INVALID_TRANSITION` (exit `1`) as above.
|
|
328
|
+
* @throws `Error` when `typeName` is not registered (see {@link resolveStateMachine}). A registered type
|
|
329
|
+
* can no longer fail to resolve a machine: REQ-STATE-08's built-in default is the last fallback.
|
|
330
|
+
*/
|
|
331
|
+
function resolveTypeTransition(memoryYaml, typeName, currentState, op, filePath = '') {
|
|
332
|
+
const machine = resolveStateMachine(memoryYaml, typeName);
|
|
333
|
+
try {
|
|
334
|
+
return resolveTransitionTarget(machine, currentState, op, filePath);
|
|
335
|
+
}
|
|
336
|
+
catch (error) {
|
|
337
|
+
if (!(error instanceof validation_1.ValidationError))
|
|
338
|
+
throw error;
|
|
339
|
+
const detail = error.issues.map((issue) => issue.message).join('; ');
|
|
340
|
+
throw new validation_1.ValidationError([
|
|
341
|
+
{
|
|
342
|
+
code: exports.E_INVALID_TRANSITION,
|
|
343
|
+
path: 'status',
|
|
344
|
+
file: filePath,
|
|
345
|
+
message: `illegal transition ${currentState} -> ${contractTarget(machine, currentState, op)} for type '${typeName}'`,
|
|
346
|
+
detail,
|
|
347
|
+
},
|
|
348
|
+
]);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* True when `status` is a state a document of this type may legitimately carry — the **full**
|
|
353
|
+
* reachable state set of `machine`, which is the union of three sources:
|
|
354
|
+
*
|
|
355
|
+
* 1. **`machine.sequence`** — every state on the forward chain.
|
|
356
|
+
* 2. **Every `machine.gates.<state>.reject` target** — `resolveTransitionTarget` returns these
|
|
357
|
+
* *verbatim* and spec-001-memory-yaml-schema's "Semantic validation (post-parse)" is explicit that
|
|
358
|
+
* such a target "need **not** be a member of `sequence`: it may revert into the chain (e.g.
|
|
359
|
+
* `pending: { reject: draft }`) or name an **off-chain decline state reached by no forward edge**".
|
|
360
|
+
* Only the gate *keys* (and `waiting` entries) are constrained to `sequence`; the reject targets
|
|
361
|
+
* are not. Omitting this arm is what task-036's first pass got wrong: the `reject` verb would write
|
|
362
|
+
* a status that this very function then declared invalid, leaving the document unmovable —
|
|
363
|
+
* a REQ-SYS-04 violation for a config shape spec-001 names by example. No type registered in
|
|
364
|
+
* `docs/self/.wingfoil/memory.yaml` currently exercises it (all three of its reject targets —
|
|
365
|
+
* `draft`, `closed`, `in-progress` — happen to be `sequence` members), so it is covered by a
|
|
366
|
+
* synthetic fixture machine in `test/memory/state-machine.test.ts`.
|
|
367
|
+
* 3. **{@link DEPRECATED_STATE}** — the reserved implicit wildcard target every type reaches via
|
|
368
|
+
* `memory.deprecate` (see {@link resolveTransitionTarget}'s `deprecate` case), never declared in
|
|
369
|
+
* any `sequence` (the `StateMachine` schema's own `.superRefine()` forbids declaring it).
|
|
370
|
+
*
|
|
371
|
+
* `machine.waiting` contributes nothing: every `waiting` entry is required to be a `sequence` member
|
|
372
|
+
* already, so it is covered by (1).
|
|
373
|
+
*
|
|
374
|
+
* Iteration over `gates` is sorted (REQ-SYS-07 — no unordered iteration in any output-affecting path);
|
|
375
|
+
* the predicate's boolean result is order-independent, but keeping the traversal deterministic keeps
|
|
376
|
+
* it so under any future change that reports *which* source matched.
|
|
377
|
+
*/
|
|
378
|
+
function isDeclaredState(machine, status) {
|
|
379
|
+
if (status === exports.DEPRECATED_STATE || machine.sequence.includes(status)) {
|
|
380
|
+
return true;
|
|
381
|
+
}
|
|
382
|
+
const gates = machine.gates ?? {};
|
|
383
|
+
return Object.keys(gates)
|
|
384
|
+
.sort()
|
|
385
|
+
.some((gateState) => gates[gateState]?.reject === status);
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Assert that `status` — a value read straight off a document's frontmatter — is a legal state for
|
|
389
|
+
* `typeName` under `machine` (REQ-STATE-01: state is derived from frontmatter; spec-010's "Validation
|
|
390
|
+
* rules": *"`status` must be a value in the type's `states.values`"*). The legal set is exactly
|
|
391
|
+
* {@link isDeclaredState}'s: `sequence` ∪ every `gates.<state>.reject` target ∪ `deprecated`.
|
|
392
|
+
*
|
|
393
|
+
* This is a distinct check from {@link resolveTransitionTarget}: that function asks "is verb `op`
|
|
394
|
+
* legal FROM `currentState`", assuming `currentState` is already known-legal; this function asks
|
|
395
|
+
* whether an arbitrary `status` string is itself a legal state for the type at all — independent of
|
|
396
|
+
* any transition attempt, e.g. when validating a document's frontmatter as read (BDD
|
|
397
|
+
* `P4.11-deliverables.feature` scenario 3, `P4.13-state-deduction.feature` scenario 3). The two must
|
|
398
|
+
* agree: any state `resolveTransitionTarget` can return must validate here, or the tool would refuse
|
|
399
|
+
* a document it wrote itself.
|
|
400
|
+
*
|
|
401
|
+
* @throws {@link ../validation.ValidationError} `E_INVALID_STATE` with the message
|
|
402
|
+
* `` invalid state '<status>' for type '<typeName>' `` when `status` is not a legal state for
|
|
403
|
+
* `typeName`. **Exit code `1`**, per spec-009-validation-strategy §3 as rewritten under
|
|
404
|
+
* `dl-032-illegal-transition-message-contract`: the code keys on the *nature* of the failure, not
|
|
405
|
+
* the pass that detected it — `2` is reserved for parse and system-integrity failures, while "every
|
|
406
|
+
* other validation failure ... including business-rule failures detected in Pass 2" exits `1`. An
|
|
407
|
+
* unrecognised `status` is understood input that a rule refused, so it is a `1`; that is why this
|
|
408
|
+
* throws the `ValidationError` constructor directly rather than `ValidationError.semantic(...)`,
|
|
409
|
+
* which hard-codes `2` for the genuine integrity checks (`loaders`, `id`, `query`). No BDD scenario
|
|
410
|
+
* pins an exit code for this message — `P4.11` sc.3 and `P4.13` sc.3 pin the text only — so the spec
|
|
411
|
+
* rule governs unopposed. (The separate `E_INVALID_TRANSITION` message/exit-code realignment that
|
|
412
|
+
* `dl-032` ratified lives in {@link resolveTypeTransition}, added by `task-045-memory-submit`.)
|
|
413
|
+
*
|
|
414
|
+
* `filePath` is only used to enrich the thrown error's `file` field (optional — defaults to `''`
|
|
415
|
+
* when no document is on hand, e.g. in pure unit tests), mirroring {@link resolveTransitionTarget}'s
|
|
416
|
+
* own `filePath` parameter.
|
|
417
|
+
*/
|
|
418
|
+
function validateFrontmatterState(machine, typeName, status, filePath = '') {
|
|
419
|
+
if (isDeclaredState(machine, status)) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
throw new validation_1.ValidationError([
|
|
423
|
+
{
|
|
424
|
+
code: exports.E_INVALID_STATE,
|
|
425
|
+
path: 'status',
|
|
426
|
+
file: filePath,
|
|
427
|
+
message: `invalid state '${status}' for type '${typeName}'`,
|
|
428
|
+
},
|
|
429
|
+
]);
|
|
430
|
+
}
|
|
431
|
+
//# sourceMappingURL=state-machine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-machine.js","sourceRoot":"","sources":["../../src/memory/state-machine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** The frontmatter key `memory.reject` sets and `memory.submit` removes (spec-010). */
|
|
2
|
+
export declare const REJECTION_REASON_FIELD = "rejection_reason";
|
|
3
|
+
/**
|
|
4
|
+
* The fields that must be filled before a submit but are not: `title` first (spec-010 requires it of
|
|
5
|
+
* every type), then each of `required` in its declared order, without duplicates. `[]` means the
|
|
6
|
+
* document may be submitted.
|
|
7
|
+
*/
|
|
8
|
+
export declare function missingRequiredFields(frontmatter: Readonly<Record<string, unknown>>, required: readonly string[]): string[];
|
|
9
|
+
/** The submitted document: `status` set to `target` and `rejection_reason` removed; nothing else changes. */
|
|
10
|
+
export declare function renderSubmitDocument(content: string, target: string): string;
|
|
11
|
+
//# sourceMappingURL=submit.d.ts.map
|