@sabaiway/agent-workflow-kit 5.11.1 → 5.11.2

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.
@@ -0,0 +1,96 @@
1
+ // flow-vocabulary.mjs — the CLOSED flow-record vocabulary (kinds, purposes, terminal lanes, the
2
+ // design seed assignment, the allowed-transition table) plus the five shared form bindings every
3
+ // validator states its refusals in: HEX64_RE, isPlainObject, isNonEmptyString, isHex64 and refuse.
4
+ // Split out of flow-record.mjs unchanged (baseline-practices tranche 3), which now re-exports the
5
+ // ten public names here; the five shared bindings stay OFF that surface (plan D3) — the leaves that
6
+ // need them import this module, so the record family's named grammars have exactly one home and no
7
+ // copy can drift.
8
+ //
9
+ // The LOWEST leaf of the family and pure form: no filesystem, no git, no CLI, no side effects on
10
+ // import, and orchestration-config.mjs (the schema version) is its only tools sibling. Imports run
11
+ // ONE way — the shape, identity, legality and manifest leaves compose this module; nothing here
12
+ // reaches back up to the facade.
13
+
14
+ import { FLOW_SCHEMA_VERSION } from './orchestration-config.mjs';
15
+
16
+ export { FLOW_SCHEMA_VERSION };
17
+
18
+ const deepFreeze = (value) => {
19
+ if (value !== null && typeof value === 'object') {
20
+ Object.values(value).forEach(deepFreeze);
21
+ Object.freeze(value);
22
+ }
23
+ return value;
24
+ };
25
+
26
+ // ── the closed vocabulary ─────────────────────────────────────────────────────────────────────────
27
+
28
+ export const CHAIN_KIND = 'chain';
29
+ export const CHAIN_PURPOSES = deepFreeze(['adoption', 'round', 'refresh', 're-baseline', 'freeze', 'unfreeze', 'park', 'resume', 'converged', 'complete']);
30
+ export const STEP_SCOPED_PURPOSES = deepFreeze(['round', 'refresh', 're-baseline', 'freeze', 'unfreeze', 'converged']);
31
+ export const PLAN_LANE_PURPOSES = deepFreeze(['adoption', 'park', 'resume', 'complete']);
32
+ export const GLOBAL_KINDS = deepFreeze(['internal-attestation', 'down-mark', 'down-mark-up', 'down-mark-clear', 'degrade-justification', 'rerun-cause', 'bookkeeping-delta', 'maintainer-override', 'consult-attestation', 'subset-attempt']);
33
+ export const FLOW_KINDS = deepFreeze([CHAIN_KIND, ...GLOBAL_KINDS]);
34
+
35
+ // Reserved lane-typed terminals (#16): converged terminates a CYCLE (its step's sequence), complete
36
+ // terminates the PLAN. Park is a resumable suspension, never a terminal (#59).
37
+ export const TERMINAL_LANES = deepFreeze({ converged: 'cycle', complete: 'plan' });
38
+
39
+ // Design §5 seed member → family assignment; the drift-guard test binds this map to the verbatim
40
+ // seed list on one side and to the shipped CHAIN_PURPOSES/GLOBAL_KINDS on the other.
41
+ export const DESIGN_SEED_ASSIGNMENT = deepFreeze({
42
+ adoption: { family: 'chain', purpose: 'adoption' },
43
+ 'round-chain': { family: 'chain', purpose: 'round' },
44
+ refresh: { family: 'chain', purpose: 'refresh' },
45
+ 're-baseline': { family: 'chain', purpose: 're-baseline' },
46
+ unfreeze: { family: 'chain', purpose: 'unfreeze' },
47
+ freeze: { family: 'chain', purpose: 'freeze' },
48
+ converged: { family: 'chain', purpose: 'converged' },
49
+ park: { family: 'chain', purpose: 'park' },
50
+ resume: { family: 'chain', purpose: 'resume' },
51
+ complete: { family: 'chain', purpose: 'complete' },
52
+ 'internal-attestation': { family: 'global', kind: 'internal-attestation' },
53
+ 'down-mark': { family: 'global', kind: 'down-mark' },
54
+ 'down-mark up': { family: 'global', kind: 'down-mark-up' },
55
+ 'down-mark clear': { family: 'global', kind: 'down-mark-clear' },
56
+ 'degrade-justification': { family: 'global', kind: 'degrade-justification' },
57
+ 'rerun-cause': { family: 'global', kind: 'rerun-cause' },
58
+ 'bookkeeping-delta': { family: 'global', kind: 'bookkeeping-delta' },
59
+ 'maintainer-override': { family: 'global', kind: 'maintainer-override' },
60
+ 'consult-attestation': { family: 'global', kind: 'consult-attestation' },
61
+ });
62
+
63
+ // The allowed-transition table — an exported frozen structure, never prose. Within a step:
64
+ // converged ends the sequence (only the unfreeze lane reopens it, and only in its own cycle);
65
+ // freeze admits only unfreeze/converged. Plan lane: park admits only resume (and both preserve the
66
+ // pre-park cycle/round); complete admits nothing; adoption is only ever the chain's first record.
67
+ // The boundary lane (between steps): the opener round, the unfreeze reopen, and a re-baseline for
68
+ // disjoint base motion that reopens nothing. The cross-step edge (the opener's prior-terminal
69
+ // reference) is enforced by validateChainSequence, distinct from the within-step successor rule.
70
+ export const ALLOWED_TRANSITIONS = deepFreeze({
71
+ stepOpening: 'round',
72
+ withinStep: {
73
+ round: ['round', 'refresh', 're-baseline', 'freeze', 'converged'],
74
+ refresh: ['round', 'refresh', 're-baseline', 'freeze', 'converged'],
75
+ 're-baseline': ['round', 'refresh', 're-baseline', 'freeze', 'converged'],
76
+ freeze: ['unfreeze', 'converged'],
77
+ unfreeze: ['round', 'refresh', 're-baseline', 'freeze', 'converged'],
78
+ converged: ['unfreeze'],
79
+ },
80
+ planLane: {
81
+ adoption: ['round', 'park', 'complete'],
82
+ park: ['resume'],
83
+ resume: ['round', 'park', 'complete'],
84
+ complete: [],
85
+ },
86
+ boundary: ['round', 'unfreeze', 're-baseline'],
87
+ });
88
+
89
+ // ── the shared form bindings (D3) — the record family's named grammars, off the public surface ────
90
+
91
+ export const HEX64_RE = /^[0-9a-f]{64}$/;
92
+ export const isPlainObject = (v) => v !== null && typeof v === 'object' && !Array.isArray(v);
93
+ export const isNonEmptyString = (v) => typeof v === 'string' && v.length > 0;
94
+ export const isHex64 = (v) => typeof v === 'string' && HEX64_RE.test(v);
95
+
96
+ export const refuse = (reason) => ({ ok: false, reason });