@catalyst-cloud/schema 0.1.49 → 0.1.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@catalyst-cloud/schema",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.51",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Typed Drizzle schema = single source of truth for the per-tenant Mirror DO SQLite store (CTC-13 / ADR-0002). Shared by the mirror Worker, the host-sync replica, and the browser OPFS replica.",
|
|
6
6
|
"license": "MIT",
|
package/src/events/registry.ts
CHANGED
|
@@ -791,68 +791,86 @@ export const durableEventTypes = {
|
|
|
791
791
|
wakes: false,
|
|
792
792
|
entity: "ticket",
|
|
793
793
|
},
|
|
794
|
-
//
|
|
795
|
-
// `phase.
|
|
796
|
-
//
|
|
794
|
+
// CTC-1530 — `intake` joins `RELAY_PHASES` at its HEAD, gated dark behind `CATALYST_INTAKE_PHASE`.
|
|
795
|
+
// This block mirrors `phase.remediate.*`'s own set exactly (no git/rebase-specific suffixes —
|
|
796
|
+
// intake never touches a branch), so the generic phase-lifecycle/park machinery every relay phase
|
|
797
|
+
// already shares works for it with no special-casing. Supersedes CTC-1597's placeholder
|
|
798
|
+
// declaration of the same family (a smaller, `phase.triage.*`-shaped set, since at that point
|
|
799
|
+
// `intake` was still dormant outside `RELAY_PHASES`) now that this ticket makes it a real,
|
|
800
|
+
// lease-backed, preemptable phase.
|
|
797
801
|
"phase.intake.abandoned": {
|
|
798
802
|
rationale:
|
|
799
|
-
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): the phase's worker abandoned it — a lifecycle terminal fact.
|
|
803
|
+
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): the phase's worker abandoned it — a lifecycle terminal fact.",
|
|
800
804
|
ingestVerb: "coordination.publish",
|
|
801
805
|
wakes: false,
|
|
802
806
|
entity: "ticket",
|
|
803
807
|
},
|
|
804
808
|
"phase.intake.boot-resume": {
|
|
805
809
|
rationale:
|
|
806
|
-
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): the daemon restarted and resumed this phase — a real coordination fact about continuity across a restart.
|
|
810
|
+
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): the daemon restarted and resumed this phase — a real coordination fact about continuity across a restart.",
|
|
807
811
|
ingestVerb: "coordination.publish",
|
|
808
812
|
wakes: false,
|
|
809
813
|
entity: "ticket",
|
|
810
814
|
},
|
|
811
|
-
"phase.intake.
|
|
815
|
+
"phase.intake.boot-resume-gated": {
|
|
812
816
|
rationale:
|
|
813
|
-
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): the
|
|
817
|
+
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): the daemon restarted but gated (did not immediately resume) this phase.",
|
|
814
818
|
ingestVerb: "coordination.publish",
|
|
815
819
|
wakes: false,
|
|
816
820
|
entity: "ticket",
|
|
817
821
|
},
|
|
818
|
-
"phase.intake.
|
|
822
|
+
"phase.intake.complete": {
|
|
819
823
|
rationale:
|
|
820
|
-
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): the phase
|
|
824
|
+
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): the phase reported success.",
|
|
821
825
|
ingestVerb: "coordination.publish",
|
|
822
|
-
wakes:
|
|
826
|
+
wakes: false,
|
|
823
827
|
entity: "ticket",
|
|
824
828
|
},
|
|
825
829
|
"phase.intake.failed": {
|
|
826
830
|
rationale:
|
|
827
|
-
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): the phase reported failure.
|
|
831
|
+
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): the phase reported failure.",
|
|
828
832
|
ingestVerb: "coordination.publish",
|
|
829
833
|
wakes: false,
|
|
830
834
|
entity: "ticket",
|
|
831
835
|
},
|
|
832
|
-
"phase.intake.
|
|
836
|
+
"phase.intake.orphan-detected": {
|
|
833
837
|
rationale:
|
|
834
|
-
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'):
|
|
838
|
+
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): an orphaned phase-agent worker was detected — a coordination fact (state discovered), not a sample.",
|
|
835
839
|
ingestVerb: "coordination.publish",
|
|
836
840
|
wakes: false,
|
|
837
841
|
entity: "ticket",
|
|
838
842
|
},
|
|
839
|
-
"phase.intake.
|
|
843
|
+
"phase.intake.park": {
|
|
840
844
|
rationale:
|
|
841
|
-
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): the phase
|
|
845
|
+
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): the intake phase was PARKED after N consecutive failures (CTC-1270) — a terminal-until-released outcome, distinct from `phase.intake.failed`, which a reader must be able to tell apart. Paired with `phase.intake.revive`.",
|
|
842
846
|
ingestVerb: "coordination.publish",
|
|
843
847
|
wakes: false,
|
|
844
848
|
entity: "ticket",
|
|
845
849
|
},
|
|
846
|
-
"phase.intake.
|
|
850
|
+
"phase.intake.preempted": {
|
|
847
851
|
rationale:
|
|
848
|
-
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'):
|
|
852
|
+
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): a higher-priority worker preempted this phase.",
|
|
853
|
+
ingestVerb: "coordination.publish",
|
|
854
|
+
wakes: false,
|
|
855
|
+
entity: "ticket",
|
|
856
|
+
},
|
|
857
|
+
"phase.intake.reclaim": {
|
|
858
|
+
rationale:
|
|
859
|
+
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): ownership of orphaned work was reclaimed by a new worker — an ownership transition akin to a lease reassignment.",
|
|
860
|
+
ingestVerb: "coordination.publish",
|
|
861
|
+
wakes: false,
|
|
862
|
+
entity: "ticket",
|
|
863
|
+
},
|
|
864
|
+
"phase.intake.resumed-after-preemption": {
|
|
865
|
+
rationale:
|
|
866
|
+
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): the phase resumed after being preempted earlier — the paired fact to *.preempted.",
|
|
849
867
|
ingestVerb: "coordination.publish",
|
|
850
868
|
wakes: false,
|
|
851
869
|
entity: "ticket",
|
|
852
870
|
},
|
|
853
871
|
"phase.intake.revive": {
|
|
854
872
|
rationale:
|
|
855
|
-
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): a
|
|
873
|
+
"ADR-0039 durable-fact example ('a phase started, completed, failed, or was preempted'): a repeated-failure park of the intake phase was revived (CTC-1270) — the paired fact to `phase.intake.park`.",
|
|
856
874
|
ingestVerb: "coordination.publish",
|
|
857
875
|
wakes: false,
|
|
858
876
|
entity: "ticket",
|
|
@@ -62,6 +62,88 @@ export function teamFromTicket(ticket: string): string | null {
|
|
|
62
62
|
return m === null ? null : m[1]!;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
/**
|
|
66
|
+
* CTC-1776 — THE ONE DOCUMENTED ORDER of `detail`'s `key=` tokens, and the reason there is one.
|
|
67
|
+
*
|
|
68
|
+
* `detail` is an APPEND-ONLY, fixed-order sequence so an operator's `blob5 LIKE '%status=…%phase=…%'`
|
|
69
|
+
* predicate keeps matching as fields are added (docs/devops.md's own recipe is written against it).
|
|
70
|
+
* A new optional field goes at the END of `buildPhaseLifecyclePoint`'s array AND at the end of this
|
|
71
|
+
* list — never inserted in the middle.
|
|
72
|
+
*
|
|
73
|
+
* `failure_class` and `round` are RESERVED here, ahead of CTC-1771 building them, so that ticket's
|
|
74
|
+
* fields land after `reason=` by construction rather than by anyone remembering to. The subsequence
|
|
75
|
+
* test in this module's spec is what enforces it.
|
|
76
|
+
*
|
|
77
|
+
* ⛔ `reason` is the ONE token whose value may contain spaces and its own `key=value` pairs — a
|
|
78
|
+
* validate row's `reason=ladder:plan-conformance=PASS type-safety=FAIL …` digest (CTC-1541/CTC-1776).
|
|
79
|
+
* A naive space-split therefore sees the digest's `step=verdict` pairs as fields of their own, which
|
|
80
|
+
* is exactly what the round-1 subsequence test missed (CTC-1776 validate round 2, CR-C). Two rules
|
|
81
|
+
* follow. (1) `reason` renders LAST of the free-text-capable tokens, so everything after it up to
|
|
82
|
+
* the next key REGISTERED HERE belongs to its value — a reader (the spec's `parseDetail`, an
|
|
83
|
+
* operator's `LIKE`) can only tell a digest pair from a field by consulting this list. (2) A field
|
|
84
|
+
* appended after `reason` MUST be registered here first: an unregistered one is indistinguishable
|
|
85
|
+
* from a digest token and is swallowed into `reason`'s value, which the spec's round-trip assertion
|
|
86
|
+
* turns into a red test rather than a silent census skew.
|
|
87
|
+
*/
|
|
88
|
+
export const PHASE_LIFECYCLE_DETAIL_ORDER = [
|
|
89
|
+
"status",
|
|
90
|
+
"ticket",
|
|
91
|
+
"phase",
|
|
92
|
+
"nonce",
|
|
93
|
+
"executor",
|
|
94
|
+
"substrate",
|
|
95
|
+
"provider",
|
|
96
|
+
"branch",
|
|
97
|
+
"base_sha",
|
|
98
|
+
"pr_number",
|
|
99
|
+
"artifact_key",
|
|
100
|
+
"reason",
|
|
101
|
+
// Reserved — CTC-1771 Phase 5.
|
|
102
|
+
"failure_class",
|
|
103
|
+
"round",
|
|
104
|
+
] as const;
|
|
105
|
+
|
|
106
|
+
/** CTC-1541/CTC-1776 — the `reason=` value a validate row carries for its per-step ladder digest.
|
|
107
|
+
* Used by BOTH the succeeded-receipt site and the failed-release site in MirrorDO.ts, so "exactly
|
|
108
|
+
* as a succeeded row does" is a shared function rather than two string literals. */
|
|
109
|
+
export const LADDER_REASON_PREFIX = "ladder:";
|
|
110
|
+
export function ladderReason(digest: string): string {
|
|
111
|
+
return `${LADDER_REASON_PREFIX}${digest}`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** CTC-1776 — the `reason=` value for a validate row whose ladder block could not be parsed at all.
|
|
115
|
+
* Deliberately NOT a `ladder:` digest: five UNREPORTED verdicts read as a verdict set, and the
|
|
116
|
+
* census must count "I could not look" apart from a real FAIL. Bare, with no cause suffix — the
|
|
117
|
+
* five causes are named in the runner's own log line (loop.ts), keyed by ticket and phase. */
|
|
118
|
+
export const VALIDATION_LADDER_UNPARSED_REASON = "validation-ladder-unparsed";
|
|
119
|
+
|
|
120
|
+
/** CTC-1776 — the one verdict that means "I could not look", mirrored from `LADDER_VERDICTS`
|
|
121
|
+
* (`apps/runner/src/validation-ladder.ts`); this package stays runner-free, same posture
|
|
122
|
+
* `apps/mirror/src/artifacts/relay-receipt.ts` already takes for the ladder's other bounds. */
|
|
123
|
+
export const UNREPORTED_LADDER_VERDICT = "UNREPORTED";
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* CTC-1776 remediate (validate round 1, CR-3) — is every `step=verdict` token in an already-rendered
|
|
127
|
+
* digest `UNREPORTED`?
|
|
128
|
+
*
|
|
129
|
+
* The succeeded-receipt site answers the same question from the parsed `RelayReceiptLadder` it holds;
|
|
130
|
+
* the FAILED-release site only ever holds the rendered digest string the runner wrote, so it needs
|
|
131
|
+
* this form. Both then map to {@link VALIDATION_LADDER_UNPARSED_REASON} rather than publishing five
|
|
132
|
+
* UNREPORTED verdicts as if they were a verdict set — the census has to count "I could not look"
|
|
133
|
+
* apart from a real FAIL on BOTH row statuses, not just on `succeeded`.
|
|
134
|
+
*
|
|
135
|
+
* An empty digest is `false`, never a vacuous `true`: `[].every(…)` is the exact shape AGENTS.md's
|
|
136
|
+
* false-clean-result rule names, and a summary with no tokens at all is not evidence of anything.
|
|
137
|
+
*/
|
|
138
|
+
export function isAllUnreportedLadderDigest(digest: string): boolean {
|
|
139
|
+
const tokens = digest.split(/\s+/).filter((token) => token.length > 0);
|
|
140
|
+
if (tokens.length === 0) return false;
|
|
141
|
+
return tokens.every((token) => {
|
|
142
|
+
const eq = token.lastIndexOf("=");
|
|
143
|
+
return eq !== -1 && token.slice(eq + 1) === UNREPORTED_LADDER_VERDICT;
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
65
147
|
/**
|
|
66
148
|
* Build one `phase.lifecycle` TelemetryPoint. Throws (never a falsy sentinel) on an unrecognized
|
|
67
149
|
* `status` — the same posture as `assertEmittable` for the event name.
|