@rightkit/social-ui 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/LICENSE-APACHE +201 -0
- package/LICENSE-MIT +21 -0
- package/README.md +40 -2
- package/dist/appName.d.ts +2 -0
- package/dist/appName.js +8 -0
- package/dist/components/ScopeSelect.d.ts +7 -0
- package/dist/components/ScopeSelect.js +6 -0
- package/dist/components/Shared.d.ts +34 -0
- package/dist/components/Shared.js +55 -0
- package/dist/data/derive.d.ts +21 -0
- package/dist/data/derive.js +47 -0
- package/dist/data/draftRules.d.ts +10 -0
- package/dist/data/draftRules.js +20 -0
- package/dist/data/engine/engineDataSource.d.ts +194 -0
- package/dist/data/engine/engineDataSource.js +836 -0
- package/dist/data/engine/errors.d.ts +13 -0
- package/dist/data/engine/errors.js +21 -0
- package/dist/data/engine/mapping.d.ts +172 -0
- package/dist/data/engine/mapping.js +1487 -0
- package/dist/data/engine/protocol.d.ts +910 -0
- package/dist/data/engine/protocol.js +67 -0
- package/dist/data/index.d.ts +18 -0
- package/dist/data/index.js +23 -0
- package/dist/data/mock/devSource.d.ts +7 -0
- package/dist/data/mock/devSource.js +10 -0
- package/dist/data/mock/fixtures-analytics.d.ts +7 -0
- package/dist/data/mock/fixtures-analytics.js +123 -0
- package/dist/data/mock/fixtures-briefs.d.ts +4 -0
- package/dist/data/mock/fixtures-briefs.js +230 -0
- package/dist/data/mock/fixtures-content.d.ts +4 -0
- package/dist/data/mock/fixtures-content.js +89 -0
- package/dist/data/mock/fixtures-digests.d.ts +3 -0
- package/dist/data/mock/fixtures-digests.js +40 -0
- package/dist/data/mock/fixtures-drafts.d.ts +2 -0
- package/dist/data/mock/fixtures-drafts.js +74 -0
- package/dist/data/mock/fixtures-gate.d.ts +3 -0
- package/dist/data/mock/fixtures-gate.js +49 -0
- package/dist/data/mock/fixtures-hooks.d.ts +2 -0
- package/dist/data/mock/fixtures-hooks.js +103 -0
- package/dist/data/mock/fixtures-inbox.d.ts +11 -0
- package/dist/data/mock/fixtures-inbox.js +213 -0
- package/dist/data/mock/fixtures-links.d.ts +5 -0
- package/dist/data/mock/fixtures-links.js +89 -0
- package/dist/data/mock/fixtures-memory.d.ts +3 -0
- package/dist/data/mock/fixtures-memory.js +148 -0
- package/dist/data/mock/fixtures-ops.d.ts +15 -0
- package/dist/data/mock/fixtures-ops.js +403 -0
- package/dist/data/mock/fixtures-optimise.d.ts +18 -0
- package/dist/data/mock/fixtures-optimise.js +221 -0
- package/dist/data/mock/fixtures-pacing.d.ts +5 -0
- package/dist/data/mock/fixtures-pacing.js +285 -0
- package/dist/data/mock/fixtures-publish.d.ts +2 -0
- package/dist/data/mock/fixtures-publish.js +129 -0
- package/dist/data/mock/fixtures-store.d.ts +10 -0
- package/dist/data/mock/fixtures-store.js +13 -0
- package/dist/data/mock/fixtures-variants.d.ts +5 -0
- package/dist/data/mock/fixtures-variants.js +138 -0
- package/dist/data/mock/fixtures.d.ts +6 -0
- package/dist/data/mock/fixtures.js +420 -0
- package/dist/data/mock/mockDataSource.d.ts +98 -0
- package/dist/data/mock/mockDataSource.js +903 -0
- package/dist/data/money.d.ts +14 -0
- package/dist/data/money.js +36 -0
- package/dist/data/platforms.d.ts +12 -0
- package/dist/data/platforms.js +26 -0
- package/dist/data/source.d.ts +196 -0
- package/dist/data/source.js +1 -0
- package/dist/data/time.d.ts +23 -0
- package/dist/data/time.js +86 -0
- package/dist/data/types.d.ts +1092 -0
- package/dist/data/types.js +3 -0
- package/dist/env.d.ts +59 -0
- package/dist/hooks/useAsync.d.ts +19 -0
- package/dist/hooks/useAsync.js +25 -0
- package/dist/index.d.ts +56 -0
- package/dist/index.js +58 -0
- package/dist/lib/host.d.ts +21 -0
- package/dist/lib/host.js +32 -0
- package/dist/lib/shell.d.ts +156 -0
- package/dist/lib/shell.js +16 -0
- package/dist/screens/AccountsScreen.d.ts +8 -0
- package/dist/screens/AccountsScreen.js +100 -0
- package/dist/screens/AnalyticsScreen.d.ts +7 -0
- package/dist/screens/AnalyticsScreen.js +64 -0
- package/dist/screens/ApprovalsScreen.d.ts +10 -0
- package/dist/screens/ApprovalsScreen.js +144 -0
- package/dist/screens/BriefsScreen.d.ts +7 -0
- package/dist/screens/BriefsScreen.js +83 -0
- package/dist/screens/CalendarScreen.d.ts +10 -0
- package/dist/screens/CalendarScreen.js +143 -0
- package/dist/screens/CampaignsScreen.d.ts +7 -0
- package/dist/screens/CampaignsScreen.js +52 -0
- package/dist/screens/ChannelMemoryScreen.d.ts +7 -0
- package/dist/screens/ChannelMemoryScreen.js +109 -0
- package/dist/screens/ContentScreen.d.ts +7 -0
- package/dist/screens/ContentScreen.js +64 -0
- package/dist/screens/DigestsScreen.d.ts +7 -0
- package/dist/screens/DigestsScreen.js +53 -0
- package/dist/screens/DraftsScreen.d.ts +10 -0
- package/dist/screens/DraftsScreen.js +108 -0
- package/dist/screens/FailuresScreen.d.ts +8 -0
- package/dist/screens/FailuresScreen.js +111 -0
- package/dist/screens/HookTestsScreen.d.ts +7 -0
- package/dist/screens/HookTestsScreen.js +54 -0
- package/dist/screens/InboxScreen.d.ts +12 -0
- package/dist/screens/InboxScreen.js +76 -0
- package/dist/screens/LinksScreen.d.ts +7 -0
- package/dist/screens/LinksScreen.js +52 -0
- package/dist/screens/PacingScreen.d.ts +7 -0
- package/dist/screens/PacingScreen.js +88 -0
- package/dist/screens/PublishJobsScreen.d.ts +7 -0
- package/dist/screens/PublishJobsScreen.js +66 -0
- package/dist/screens/SuggestionsScreen.d.ts +8 -0
- package/dist/screens/SuggestionsScreen.js +94 -0
- package/dist/screens/TextGateScreen.d.ts +7 -0
- package/dist/screens/TextGateScreen.js +111 -0
- package/dist/screens/ThreadsScreen.d.ts +8 -0
- package/dist/screens/ThreadsScreen.js +113 -0
- package/dist/screens/TypedBriefsScreen.d.ts +7 -0
- package/dist/screens/TypedBriefsScreen.js +75 -0
- package/dist/screens/labels.d.ts +121 -0
- package/dist/screens/labels.js +272 -0
- package/package.json +56 -3
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/** Every method the shell forwards. Keep in step with UI_METHODS in src-tauri/src/lib.rs. */
|
|
2
|
+
export const UI_METHODS = [
|
|
3
|
+
"channel.list",
|
|
4
|
+
"calendar.list",
|
|
5
|
+
"calendar.get",
|
|
6
|
+
"calendar.approve",
|
|
7
|
+
"calendar.reject",
|
|
8
|
+
"calendar.pause",
|
|
9
|
+
"calendar.resume",
|
|
10
|
+
"brief.get",
|
|
11
|
+
"account.list",
|
|
12
|
+
"account.get",
|
|
13
|
+
"account.pause",
|
|
14
|
+
"account.resume",
|
|
15
|
+
"account.disconnect",
|
|
16
|
+
"draft.list",
|
|
17
|
+
"draft.approve",
|
|
18
|
+
"draft.mark_posted",
|
|
19
|
+
"draft.skip",
|
|
20
|
+
"publish.get",
|
|
21
|
+
"publish.list",
|
|
22
|
+
"optimise.list",
|
|
23
|
+
"optimise.get",
|
|
24
|
+
"optimise.accept",
|
|
25
|
+
"optimise.dismiss",
|
|
26
|
+
"allowance.get",
|
|
27
|
+
"spend.report",
|
|
28
|
+
"price.list",
|
|
29
|
+
"campaign.list",
|
|
30
|
+
"link.list",
|
|
31
|
+
"link.attribution",
|
|
32
|
+
"hook_test.list",
|
|
33
|
+
"hook_test.get",
|
|
34
|
+
"digest.list",
|
|
35
|
+
"digest.get",
|
|
36
|
+
"digest.applied",
|
|
37
|
+
"content.list",
|
|
38
|
+
"content.get",
|
|
39
|
+
"content.experiment_summary",
|
|
40
|
+
"gate_policy.get",
|
|
41
|
+
"gate.check",
|
|
42
|
+
"gate.records",
|
|
43
|
+
"brief_out.list",
|
|
44
|
+
"brief_out.get",
|
|
45
|
+
"delivery.list",
|
|
46
|
+
"delivery.get",
|
|
47
|
+
"dispatch.list",
|
|
48
|
+
"memory.get",
|
|
49
|
+
"memory.history",
|
|
50
|
+
"proof.list",
|
|
51
|
+
"typed_brief.list",
|
|
52
|
+
"typed_brief.get",
|
|
53
|
+
"variant.list",
|
|
54
|
+
"analytics.list",
|
|
55
|
+
"analytics.summary",
|
|
56
|
+
"metric_import.list",
|
|
57
|
+
"heartbeat.status",
|
|
58
|
+
"store.restore_receipts",
|
|
59
|
+
"inbox.list",
|
|
60
|
+
"inbox.get",
|
|
61
|
+
"inbox.stats",
|
|
62
|
+
"publish.next",
|
|
63
|
+
"publish.quota_get",
|
|
64
|
+
"doctor",
|
|
65
|
+
"rightkit.settings.get",
|
|
66
|
+
"rightkit.settings.patch",
|
|
67
|
+
];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DataSource } from "./source.js";
|
|
2
|
+
export type * from "./types.js";
|
|
3
|
+
export type { DataSource, MockControls, DataError, DataErrorCode, EngineOnlyErrorCode, Result, UnmappedAccount } from "./source.js";
|
|
4
|
+
export { SOCIAL_PLATFORMS, isSocialPlatform } from "./platforms.js";
|
|
5
|
+
export { EngineDataSource } from "./engine/engineDataSource.js";
|
|
6
|
+
export { accountOrdinals, awaitingDecision, charCount, isApproved, jobsByAccount, mediaReady, shortHash } from "./derive.js";
|
|
7
|
+
export type { AccountOrdinal } from "./derive.js";
|
|
8
|
+
export * from "./time.js";
|
|
9
|
+
export { disclosureFound, firstSentence } from "./draftRules.js";
|
|
10
|
+
export { formatMicro, formatMilli, groupDigits, monthOfInstant } from "./money.js";
|
|
11
|
+
/**
|
|
12
|
+
* The source the desktop runs on. A release build is the engine only: the mock, its JSON fixtures and the shared
|
|
13
|
+
* data helpers load through a dynamic import behind import.meta.env?.DEV || __RIGHTKIT_MOCK__ (RIGHTKIT_MOCK=1, UI QA only), which Vite folds to false, so they are not
|
|
14
|
+
* in dist/ (right-release dist-scan, declared in right-release.config.mjs, forbids their chunk names and the markers
|
|
15
|
+
* in src/data/release-forbid.txt). In dev the engine is used only inside the Tauri shell with
|
|
16
|
+
* VITE_RIGHTKIT_DATA=engine; everything else is the mock, so the browser preview keeps its "Mock data" banner.
|
|
17
|
+
*/
|
|
18
|
+
export declare function selectDataSource(): Promise<DataSource>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Public surface of the operator data layer. Screens import from here, never from mock/ or engine/.
|
|
2
|
+
import { isTauri } from "../lib/host.js";
|
|
3
|
+
import { EngineDataSource } from "./engine/engineDataSource.js";
|
|
4
|
+
export { SOCIAL_PLATFORMS, isSocialPlatform } from "./platforms.js";
|
|
5
|
+
export { EngineDataSource } from "./engine/engineDataSource.js";
|
|
6
|
+
export { accountOrdinals, awaitingDecision, charCount, isApproved, jobsByAccount, mediaReady, shortHash } from "./derive.js";
|
|
7
|
+
export * from "./time.js";
|
|
8
|
+
export { disclosureFound, firstSentence } from "./draftRules.js";
|
|
9
|
+
export { formatMicro, formatMilli, groupDigits, monthOfInstant } from "./money.js";
|
|
10
|
+
/**
|
|
11
|
+
* The source the desktop runs on. A release build is the engine only: the mock, its JSON fixtures and the shared
|
|
12
|
+
* data helpers load through a dynamic import behind import.meta.env?.DEV || __RIGHTKIT_MOCK__ (RIGHTKIT_MOCK=1, UI QA only), which Vite folds to false, so they are not
|
|
13
|
+
* in dist/ (right-release dist-scan, declared in right-release.config.mjs, forbids their chunk names and the markers
|
|
14
|
+
* in src/data/release-forbid.txt). In dev the engine is used only inside the Tauri shell with
|
|
15
|
+
* VITE_RIGHTKIT_DATA=engine; everything else is the mock, so the browser preview keeps its "Mock data" banner.
|
|
16
|
+
*/
|
|
17
|
+
export async function selectDataSource() {
|
|
18
|
+
if (import.meta.env?.DEV || (typeof __RIGHTKIT_MOCK__ === "boolean" && __RIGHTKIT_MOCK__)) {
|
|
19
|
+
const { pickDevSource } = await import("./mock/devSource.js");
|
|
20
|
+
return pickDevSource(isTauri(), () => new EngineDataSource());
|
|
21
|
+
}
|
|
22
|
+
return new EngineDataSource();
|
|
23
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DataSource } from "../source.js";
|
|
2
|
+
/**
|
|
3
|
+
* The engine only when asked for and reachable (Tauri plus either VITE_RIGHTKIT_DATA=engine, which plain `pnpm dev`
|
|
4
|
+
* and `tauri dev` still use, or the init value the UI QA shell sets from its world, `RIGHTKIT_QA_APP_DATA_SOURCE=engine`);
|
|
5
|
+
* otherwise the mock.
|
|
6
|
+
*/
|
|
7
|
+
export declare function pickDevSource(hostAvailable: boolean, engine: () => DataSource): DataSource;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { MockDataSource } from "./mockDataSource.js";
|
|
2
|
+
/**
|
|
3
|
+
* The engine only when asked for and reachable (Tauri plus either VITE_RIGHTKIT_DATA=engine, which plain `pnpm dev`
|
|
4
|
+
* and `tauri dev` still use, or the init value the UI QA shell sets from its world, `RIGHTKIT_QA_APP_DATA_SOURCE=engine`);
|
|
5
|
+
* otherwise the mock.
|
|
6
|
+
*/
|
|
7
|
+
export function pickDevSource(hostAvailable, engine) {
|
|
8
|
+
const asked = import.meta.env?.VITE_RIGHTKIT_DATA === "engine" || window.__RIGHTKIT_QA_DATA_SOURCE__ === "engine";
|
|
9
|
+
return hostAvailable && asked ? engine() : new MockDataSource();
|
|
10
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AnalyticsObservation, AnalyticsPost, MetricImport } from "../types.js";
|
|
2
|
+
/** The facts of each post, before its metrics. */
|
|
3
|
+
export declare const FIXTURE_ANALYTICS_POSTS: Omit<AnalyticsPost, "metrics">[];
|
|
4
|
+
/** Every stored observation. API rows come from a pull; the manual row comes from a fixture import. */
|
|
5
|
+
export declare const FIXTURE_ANALYTICS_OBSERVATIONS: AnalyticsObservation[];
|
|
6
|
+
/** Every committed manual import in the first channel. */
|
|
7
|
+
export declare const FIXTURE_METRIC_IMPORTS: MetricImport[];
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { SCOPE_ALPHA } from "./fixtures-optimise.js";
|
|
2
|
+
const POST_ONE = "fixture-job-analytics-1";
|
|
3
|
+
const POST_TWO = "fixture-job-analytics-2";
|
|
4
|
+
/** The facts of each post, before its metrics. */
|
|
5
|
+
export const FIXTURE_ANALYTICS_POSTS = [
|
|
6
|
+
{
|
|
7
|
+
scopeId: SCOPE_ALPHA,
|
|
8
|
+
jobId: POST_ONE,
|
|
9
|
+
platform: "instagram",
|
|
10
|
+
remotePostId: "fixture-ig-0001",
|
|
11
|
+
publishedAtUtc: "2026-09-02T10:00:00Z",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
scopeId: SCOPE_ALPHA,
|
|
15
|
+
jobId: POST_TWO,
|
|
16
|
+
platform: "youtube",
|
|
17
|
+
remotePostId: "fixture-yt-0002",
|
|
18
|
+
publishedAtUtc: "2026-09-20T18:00:00Z",
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
/** Every stored observation. API rows come from a pull; the manual row comes from a fixture import. */
|
|
22
|
+
export const FIXTURE_ANALYTICS_OBSERVATIONS = [
|
|
23
|
+
// Post one, first pull: views only.
|
|
24
|
+
{
|
|
25
|
+
scopeId: SCOPE_ALPHA,
|
|
26
|
+
jobId: POST_ONE,
|
|
27
|
+
metric: "views",
|
|
28
|
+
state: "value",
|
|
29
|
+
value: "1520",
|
|
30
|
+
observedAtUtc: "2026-09-03T10:00:00Z",
|
|
31
|
+
window: "lifetime",
|
|
32
|
+
source: "api",
|
|
33
|
+
pullId: "fixture-pull-0903",
|
|
34
|
+
importId: null,
|
|
35
|
+
},
|
|
36
|
+
// Post one, second pull: views, saves, and shares, which this platform does not provide.
|
|
37
|
+
{
|
|
38
|
+
scopeId: SCOPE_ALPHA,
|
|
39
|
+
jobId: POST_ONE,
|
|
40
|
+
metric: "views",
|
|
41
|
+
state: "value",
|
|
42
|
+
value: "4210",
|
|
43
|
+
observedAtUtc: "2026-10-01T10:00:00Z",
|
|
44
|
+
window: "lifetime",
|
|
45
|
+
source: "api",
|
|
46
|
+
pullId: "fixture-pull-1001",
|
|
47
|
+
importId: null,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
scopeId: SCOPE_ALPHA,
|
|
51
|
+
jobId: POST_ONE,
|
|
52
|
+
metric: "saves",
|
|
53
|
+
state: "value",
|
|
54
|
+
value: "88",
|
|
55
|
+
observedAtUtc: "2026-10-01T10:00:00Z",
|
|
56
|
+
window: "lifetime",
|
|
57
|
+
source: "api",
|
|
58
|
+
pullId: "fixture-pull-1001",
|
|
59
|
+
importId: null,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
scopeId: SCOPE_ALPHA,
|
|
63
|
+
jobId: POST_ONE,
|
|
64
|
+
metric: "shares",
|
|
65
|
+
state: "unavailable",
|
|
66
|
+
value: null,
|
|
67
|
+
observedAtUtc: "2026-10-01T10:00:00Z",
|
|
68
|
+
window: "lifetime",
|
|
69
|
+
source: "api",
|
|
70
|
+
pullId: "fixture-pull-1001",
|
|
71
|
+
importId: null,
|
|
72
|
+
},
|
|
73
|
+
// Post two: an API pull, then a manual export of a metric the API does not give.
|
|
74
|
+
{
|
|
75
|
+
scopeId: SCOPE_ALPHA,
|
|
76
|
+
jobId: POST_TWO,
|
|
77
|
+
metric: "views",
|
|
78
|
+
state: "value",
|
|
79
|
+
value: "512",
|
|
80
|
+
observedAtUtc: "2026-09-25T09:00:00Z",
|
|
81
|
+
window: "lifetime",
|
|
82
|
+
source: "api",
|
|
83
|
+
pullId: "fixture-pull-0925",
|
|
84
|
+
importId: null,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
scopeId: SCOPE_ALPHA,
|
|
88
|
+
jobId: POST_TWO,
|
|
89
|
+
metric: "views",
|
|
90
|
+
state: "value",
|
|
91
|
+
value: "733",
|
|
92
|
+
observedAtUtc: "2026-10-01T10:00:00Z",
|
|
93
|
+
window: "lifetime",
|
|
94
|
+
source: "api",
|
|
95
|
+
pullId: "fixture-pull-1001",
|
|
96
|
+
importId: null,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
scopeId: SCOPE_ALPHA,
|
|
100
|
+
jobId: POST_TWO,
|
|
101
|
+
metric: "avg_view_percent",
|
|
102
|
+
state: "value",
|
|
103
|
+
value: "41.5",
|
|
104
|
+
observedAtUtc: "2026-10-05T09:00:00Z",
|
|
105
|
+
window: null,
|
|
106
|
+
source: "manual_export",
|
|
107
|
+
pullId: null,
|
|
108
|
+
importId: "fixture-import-retention-1",
|
|
109
|
+
},
|
|
110
|
+
];
|
|
111
|
+
/** Every committed manual import in the first channel. */
|
|
112
|
+
export const FIXTURE_METRIC_IMPORTS = [
|
|
113
|
+
{
|
|
114
|
+
scopeId: SCOPE_ALPHA,
|
|
115
|
+
importId: "fixture-import-retention-1",
|
|
116
|
+
platform: "youtube",
|
|
117
|
+
sourceNote: "Fixture export: an invented retention table, saved by hand",
|
|
118
|
+
source: "manual_export",
|
|
119
|
+
createdAtUtc: "2026-10-05T09:05:00Z",
|
|
120
|
+
rowsWritten: 1,
|
|
121
|
+
observationsWritten: 1,
|
|
122
|
+
},
|
|
123
|
+
];
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { DeliveryEnvelope, DispatchAttempt, OutgoingBriefDetail } from "../types.js";
|
|
2
|
+
export declare const FIXTURE_BRIEFS: OutgoingBriefDetail[];
|
|
3
|
+
export declare const FIXTURE_DELIVERIES: DeliveryEnvelope[];
|
|
4
|
+
export declare const FIXTURE_DISPATCH_ATTEMPTS: DispatchAttempt[];
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { SCOPE_ALPHA } from "./fixtures-optimise.js";
|
|
2
|
+
const CHANNEL = { venture: "fixture-alpha", channel: "alpha-shorts", account: "alpha-main" };
|
|
3
|
+
const INPUT_HASH = `blake3:${"5".repeat(64)}`;
|
|
4
|
+
export const FIXTURE_BRIEFS = [
|
|
5
|
+
{
|
|
6
|
+
// Issued, not yet delivered. Its first attempt found no engine, and its second timed out.
|
|
7
|
+
scopeId: SCOPE_ALPHA,
|
|
8
|
+
requestId: "fixture-req-0001",
|
|
9
|
+
briefId: "brief.fixture-0001",
|
|
10
|
+
revision: 1,
|
|
11
|
+
state: "issued",
|
|
12
|
+
createdAtUtc: "2026-10-08T09:00:00Z",
|
|
13
|
+
updatedAtUtc: "2026-10-08T09:00:00Z",
|
|
14
|
+
summary: {
|
|
15
|
+
briefType: "talking_head",
|
|
16
|
+
platforms: ["youtube_shorts"],
|
|
17
|
+
deliverables: ["video"],
|
|
18
|
+
hook: "Fixture hook: the puddle that never dries.",
|
|
19
|
+
reviewMode: "manual",
|
|
20
|
+
policyRevision: 3,
|
|
21
|
+
stageCount: 1,
|
|
22
|
+
},
|
|
23
|
+
document: {
|
|
24
|
+
contract: "content-brief",
|
|
25
|
+
contractVersion: "1.1.0",
|
|
26
|
+
briefId: "brief.fixture-0001",
|
|
27
|
+
revision: 1,
|
|
28
|
+
briefType: "talking_head",
|
|
29
|
+
channel: CHANNEL,
|
|
30
|
+
platforms: ["youtube_shorts"],
|
|
31
|
+
deliverables: ["video"],
|
|
32
|
+
hook: "Fixture hook: the puddle that never dries.",
|
|
33
|
+
review: { mode: "manual", policyRevision: 3 },
|
|
34
|
+
stages: [{ id: "script", requestId: "req.fixture-0001.script", inputHash: INPUT_HASH, dependsOn: [] }],
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
// Delivered: one envelope is stored for it, and its attempt succeeded.
|
|
39
|
+
scopeId: SCOPE_ALPHA,
|
|
40
|
+
requestId: "fixture-req-0002",
|
|
41
|
+
briefId: "brief.fixture-0002",
|
|
42
|
+
revision: 1,
|
|
43
|
+
state: "delivered",
|
|
44
|
+
createdAtUtc: "2026-10-09T09:45:00Z",
|
|
45
|
+
updatedAtUtc: "2026-10-09T10:15:00Z",
|
|
46
|
+
summary: {
|
|
47
|
+
briefType: "talking_head",
|
|
48
|
+
platforms: ["youtube_shorts"],
|
|
49
|
+
deliverables: ["video"],
|
|
50
|
+
hook: "Fixture hook: the slow reveal.",
|
|
51
|
+
reviewMode: "manual",
|
|
52
|
+
policyRevision: 3,
|
|
53
|
+
stageCount: 1,
|
|
54
|
+
},
|
|
55
|
+
document: {
|
|
56
|
+
contract: "content-brief",
|
|
57
|
+
contractVersion: "1.1.0",
|
|
58
|
+
briefId: "brief.fixture-0002",
|
|
59
|
+
revision: 1,
|
|
60
|
+
briefType: "talking_head",
|
|
61
|
+
channel: CHANNEL,
|
|
62
|
+
platforms: ["youtube_shorts"],
|
|
63
|
+
deliverables: ["video"],
|
|
64
|
+
hook: "Fixture hook: the slow reveal.",
|
|
65
|
+
review: { mode: "manual", policyRevision: 3 },
|
|
66
|
+
stages: [{ id: "script", requestId: "req.fixture-0002.script", inputHash: INPUT_HASH, dependsOn: [] }],
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
];
|
|
70
|
+
/** A fixture brief document for the two multi-deliverable briefs below. */
|
|
71
|
+
function twoDeliverableBrief(requestId, briefId, state, hook, createdAtUtc, updatedAtUtc) {
|
|
72
|
+
return {
|
|
73
|
+
scopeId: SCOPE_ALPHA,
|
|
74
|
+
requestId,
|
|
75
|
+
briefId,
|
|
76
|
+
revision: 1,
|
|
77
|
+
state,
|
|
78
|
+
createdAtUtc,
|
|
79
|
+
updatedAtUtc,
|
|
80
|
+
summary: {
|
|
81
|
+
briefType: "talking_head",
|
|
82
|
+
platforms: ["youtube_shorts"],
|
|
83
|
+
deliverables: ["reels", "square"],
|
|
84
|
+
hook,
|
|
85
|
+
reviewMode: "manual",
|
|
86
|
+
policyRevision: 3,
|
|
87
|
+
stageCount: 1,
|
|
88
|
+
},
|
|
89
|
+
document: {
|
|
90
|
+
contract: "content-brief",
|
|
91
|
+
contractVersion: "1.1.0",
|
|
92
|
+
briefId,
|
|
93
|
+
revision: 1,
|
|
94
|
+
briefType: "talking_head",
|
|
95
|
+
channel: CHANNEL,
|
|
96
|
+
platforms: ["youtube_shorts"],
|
|
97
|
+
deliverables: ["reels", "square"],
|
|
98
|
+
hook,
|
|
99
|
+
review: { mode: "manual", policyRevision: 3 },
|
|
100
|
+
stages: [{ id: "script", requestId: `req.${requestId}.script`, inputHash: INPUT_HASH, dependsOn: [] }],
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** A fixture video envelope for one deliverable of a two-deliverable brief. */
|
|
105
|
+
function deliverableEnvelope(requestId, briefId, deliverable, acceptedAtUtc) {
|
|
106
|
+
const envelopeId = `fixture-envelope-${requestId}-${deliverable}`;
|
|
107
|
+
return {
|
|
108
|
+
scopeId: SCOPE_ALPHA,
|
|
109
|
+
envelopeId,
|
|
110
|
+
requestId,
|
|
111
|
+
deliverable,
|
|
112
|
+
briefId,
|
|
113
|
+
briefRevision: 1,
|
|
114
|
+
acceptedAtUtc,
|
|
115
|
+
document: {
|
|
116
|
+
contract: "delivery-envelope",
|
|
117
|
+
contractVersion: "1.1.0",
|
|
118
|
+
envelopeId,
|
|
119
|
+
briefId,
|
|
120
|
+
briefRevision: 1,
|
|
121
|
+
media: [{ hash: `blake3:${(deliverable === "reels" ? "7" : "8").repeat(64)}` }],
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// Two more briefs: one delivered with an envelope for each of two deliverables, and one partial because the
|
|
126
|
+
// engine refused the second deliverable as a paid route.
|
|
127
|
+
FIXTURE_BRIEFS.push(twoDeliverableBrief("fixture-req-0003", "brief.fixture-0003", "partial", "Fixture hook: the half-finished wave.", "2026-10-10T09:00:00Z", "2026-10-10T09:30:00Z"), twoDeliverableBrief("fixture-req-0004", "brief.fixture-0004", "delivered", "Fixture hook: both sizes at once.", "2026-10-11T09:00:00Z", "2026-10-11T09:20:00Z"));
|
|
128
|
+
export const FIXTURE_DELIVERIES = [
|
|
129
|
+
deliverableEnvelope("fixture-req-0003", "brief.fixture-0003", "reels", "2026-10-10T09:30:00Z"),
|
|
130
|
+
deliverableEnvelope("fixture-req-0004", "brief.fixture-0004", "reels", "2026-10-11T09:20:00Z"),
|
|
131
|
+
deliverableEnvelope("fixture-req-0004", "brief.fixture-0004", "square", "2026-10-11T09:20:00Z"),
|
|
132
|
+
{
|
|
133
|
+
scopeId: SCOPE_ALPHA,
|
|
134
|
+
envelopeId: "fixture-envelope-0002",
|
|
135
|
+
requestId: "fixture-req-0002",
|
|
136
|
+
deliverable: "",
|
|
137
|
+
briefId: "brief.fixture-0002",
|
|
138
|
+
briefRevision: 1,
|
|
139
|
+
acceptedAtUtc: "2026-10-09T10:15:00Z",
|
|
140
|
+
document: {
|
|
141
|
+
contract: "delivery-envelope",
|
|
142
|
+
contractVersion: "1.1.0",
|
|
143
|
+
envelopeId: "fixture-envelope-0002",
|
|
144
|
+
briefId: "brief.fixture-0002",
|
|
145
|
+
briefRevision: 1,
|
|
146
|
+
media: [{ hash: `blake3:${"6".repeat(64)}` }],
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
];
|
|
150
|
+
export const FIXTURE_DISPATCH_ATTEMPTS = [
|
|
151
|
+
{
|
|
152
|
+
// The engine path was not set, so nothing was spawned.
|
|
153
|
+
scopeId: SCOPE_ALPHA,
|
|
154
|
+
attemptId: 1,
|
|
155
|
+
requestId: "fixture-req-0001",
|
|
156
|
+
engine: "cutright",
|
|
157
|
+
startedAtUtc: "2026-10-08T09:05:00Z",
|
|
158
|
+
finishedAtUtc: "2026-10-08T09:05:00Z",
|
|
159
|
+
exitCode: null,
|
|
160
|
+
outcome: "engine_missing",
|
|
161
|
+
stderrTail: null,
|
|
162
|
+
message: "Fixture: the engine path is not set, so nothing ran.",
|
|
163
|
+
producedDeliverables: [],
|
|
164
|
+
skipped: [],
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
// The wall clock ran out and the process tree was killed, so there is no exit code.
|
|
168
|
+
scopeId: SCOPE_ALPHA,
|
|
169
|
+
attemptId: 2,
|
|
170
|
+
requestId: "fixture-req-0001",
|
|
171
|
+
engine: "cutright",
|
|
172
|
+
startedAtUtc: "2026-10-08T09:10:00Z",
|
|
173
|
+
finishedAtUtc: "2026-10-08T09:20:00Z",
|
|
174
|
+
exitCode: null,
|
|
175
|
+
outcome: "timed_out",
|
|
176
|
+
stderrTail: "Fixture stderr: the render step was still running when the limit was reached.",
|
|
177
|
+
message: "Fixture: the engine did not finish within 600000 ms. The process tree was ended.",
|
|
178
|
+
producedDeliverables: [],
|
|
179
|
+
skipped: [],
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
scopeId: SCOPE_ALPHA,
|
|
183
|
+
attemptId: 3,
|
|
184
|
+
requestId: "fixture-req-0002",
|
|
185
|
+
engine: "cutright",
|
|
186
|
+
startedAtUtc: "2026-10-09T10:00:00Z",
|
|
187
|
+
finishedAtUtc: "2026-10-09T10:04:30Z",
|
|
188
|
+
exitCode: 0,
|
|
189
|
+
outcome: "delivered",
|
|
190
|
+
stderrTail: "",
|
|
191
|
+
message: "Fixture: one envelope was named and accepted.",
|
|
192
|
+
producedDeliverables: [],
|
|
193
|
+
skipped: [],
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
// Partial: the engine delivered reels and refused the paid-route square deliverable.
|
|
197
|
+
scopeId: SCOPE_ALPHA,
|
|
198
|
+
attemptId: 4,
|
|
199
|
+
requestId: "fixture-req-0003",
|
|
200
|
+
engine: "genright",
|
|
201
|
+
startedAtUtc: "2026-10-10T09:10:00Z",
|
|
202
|
+
finishedAtUtc: "2026-10-10T09:30:00Z",
|
|
203
|
+
exitCode: 0,
|
|
204
|
+
outcome: "partial",
|
|
205
|
+
stderrTail: "",
|
|
206
|
+
message: "Fixture: 1 envelope(s) accepted; the engine skipped or refused part of the request.",
|
|
207
|
+
producedDeliverables: ["reels"],
|
|
208
|
+
skipped: [
|
|
209
|
+
{
|
|
210
|
+
deliverable: "square",
|
|
211
|
+
code: "spend_authorisation_required",
|
|
212
|
+
message: "Fixture: this deliverable uses a paid route and no spend was authorised.",
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
scopeId: SCOPE_ALPHA,
|
|
218
|
+
attemptId: 5,
|
|
219
|
+
requestId: "fixture-req-0004",
|
|
220
|
+
engine: "genright",
|
|
221
|
+
startedAtUtc: "2026-10-11T09:05:00Z",
|
|
222
|
+
finishedAtUtc: "2026-10-11T09:20:00Z",
|
|
223
|
+
exitCode: 0,
|
|
224
|
+
outcome: "delivered",
|
|
225
|
+
stderrTail: "",
|
|
226
|
+
message: "Fixture: 2 envelope(s) accepted; the engine produced everything requested.",
|
|
227
|
+
producedDeliverables: ["reels", "square"],
|
|
228
|
+
skipped: [],
|
|
229
|
+
},
|
|
230
|
+
];
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ContentExperimentSummary, ContentRecord, ContentVariant } from "../types.js";
|
|
2
|
+
export declare const FIXTURE_CONTENT: ContentRecord[];
|
|
3
|
+
export declare const FIXTURE_CONTENT_VARIANTS: ContentVariant[];
|
|
4
|
+
export declare const FIXTURE_CONTENT_SUMMARIES: ContentExperimentSummary[];
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { SCOPE_ALPHA } from "./fixtures-optimise.js";
|
|
2
|
+
export const FIXTURE_CONTENT = [
|
|
3
|
+
{
|
|
4
|
+
// Active, with two caption variants and one call to action. No occurrence has reached the minimum.
|
|
5
|
+
id: "fixture-clip-puddle",
|
|
6
|
+
scopeId: SCOPE_ALPHA,
|
|
7
|
+
title: "Fixture clip: puddle chorus",
|
|
8
|
+
media: [{ hash: "blake3:0f0f0f0f0f0f0f01", kind: "video", durationMs: 42000 }],
|
|
9
|
+
baseCaption: "Fixture base caption for the puddle chorus.",
|
|
10
|
+
evergreen: true,
|
|
11
|
+
cooldownDays: 14,
|
|
12
|
+
expiresAtUtc: "2027-03-31T23:59:59Z",
|
|
13
|
+
state: "active",
|
|
14
|
+
withdrawalReason: null,
|
|
15
|
+
revision: 4,
|
|
16
|
+
createdAtUtc: "2026-09-01T09:00:00Z",
|
|
17
|
+
updatedAtUtc: "2026-10-06T10:00:00Z",
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
// Withdrawn: final. Its planned occurrences were cancelled when it was withdrawn.
|
|
21
|
+
id: "fixture-clip-lighthouse",
|
|
22
|
+
scopeId: SCOPE_ALPHA,
|
|
23
|
+
title: "Fixture clip: lighthouse still",
|
|
24
|
+
media: [{ hash: "blake3:1a2b3c4d5e6f7081", kind: "image", durationMs: null }],
|
|
25
|
+
baseCaption: "Fixture base caption for the lighthouse still.",
|
|
26
|
+
evergreen: false,
|
|
27
|
+
cooldownDays: 7,
|
|
28
|
+
expiresAtUtc: null,
|
|
29
|
+
state: "withdrawn",
|
|
30
|
+
withdrawalReason: "Fixture reason: the stock image licence ended.",
|
|
31
|
+
revision: 3,
|
|
32
|
+
createdAtUtc: "2026-08-20T09:00:00Z",
|
|
33
|
+
updatedAtUtc: "2026-09-30T12:00:00Z",
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
export const FIXTURE_CONTENT_VARIANTS = [
|
|
37
|
+
{
|
|
38
|
+
id: "fixture-cap-a",
|
|
39
|
+
scopeId: SCOPE_ALPHA,
|
|
40
|
+
contentId: "fixture-clip-puddle",
|
|
41
|
+
kind: "caption",
|
|
42
|
+
text: "Fixture caption A: the chorus, with the puddle in view.",
|
|
43
|
+
createdAtUtc: "2026-09-01T09:05:00Z",
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: "fixture-cap-b",
|
|
47
|
+
scopeId: SCOPE_ALPHA,
|
|
48
|
+
contentId: "fixture-clip-puddle",
|
|
49
|
+
kind: "caption",
|
|
50
|
+
text: "Fixture caption B: the chorus, sung twice.",
|
|
51
|
+
createdAtUtc: "2026-09-01T09:06:00Z",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "fixture-cta-a",
|
|
55
|
+
scopeId: SCOPE_ALPHA,
|
|
56
|
+
contentId: "fixture-clip-puddle",
|
|
57
|
+
kind: "cta",
|
|
58
|
+
text: "Fixture call to action: watch the full episode.",
|
|
59
|
+
createdAtUtc: "2026-09-01T09:07:00Z",
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
export const FIXTURE_CONTENT_SUMMARIES = [
|
|
63
|
+
{
|
|
64
|
+
// Insufficient evidence: both caption variants are below 20 published occurrences, and only one
|
|
65
|
+
// call to action is stored. The engine names no winner, and neither does this screen.
|
|
66
|
+
scopeId: SCOPE_ALPHA,
|
|
67
|
+
contentId: "fixture-clip-puddle",
|
|
68
|
+
minOccurrences: 20,
|
|
69
|
+
verdict: "insufficient_evidence",
|
|
70
|
+
reason: "caption variant fixture-cap-a has 3 published occurrences; the minimum is 20; caption variant fixture-cap-b has 2 published occurrences; the minimum is 20; fewer than two cta variants are stored (1); cta variant fixture-cta-a has 1 published occurrences; the minimum is 20",
|
|
71
|
+
caption: [
|
|
72
|
+
{ variantId: "fixture-cap-a", text: "Fixture caption A: the chorus, with the puddle in view.", planned: 1, published: 3, cancelled: 0, meetsMinimum: false },
|
|
73
|
+
{ variantId: "fixture-cap-b", text: "Fixture caption B: the chorus, sung twice.", planned: 2, published: 2, cancelled: 1, meetsMinimum: false },
|
|
74
|
+
],
|
|
75
|
+
cta: [
|
|
76
|
+
{ variantId: "fixture-cta-a", text: "Fixture call to action: watch the full episode.", planned: 0, published: 1, cancelled: 0, meetsMinimum: false },
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
// The withdrawn record has no variants, so both kinds are below two variants.
|
|
81
|
+
scopeId: SCOPE_ALPHA,
|
|
82
|
+
contentId: "fixture-clip-lighthouse",
|
|
83
|
+
minOccurrences: 20,
|
|
84
|
+
verdict: "insufficient_evidence",
|
|
85
|
+
reason: "fewer than two caption variants are stored (0); fewer than two cta variants are stored (0)",
|
|
86
|
+
caption: [],
|
|
87
|
+
cta: [],
|
|
88
|
+
},
|
|
89
|
+
];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { SCOPE_ALPHA } from "./fixtures-optimise.js";
|
|
2
|
+
export const FIXTURE_DIGESTS = [
|
|
3
|
+
{
|
|
4
|
+
id: "fixture-digest-2026-10-05",
|
|
5
|
+
scopeId: SCOPE_ALPHA,
|
|
6
|
+
digestDate: "2026-10-05",
|
|
7
|
+
entries: [
|
|
8
|
+
{
|
|
9
|
+
// Applied: became one draft calendar entry.
|
|
10
|
+
id: "fixture-finding-a",
|
|
11
|
+
topic: "Fixture topic: bedtime routines",
|
|
12
|
+
finding: "Fixture finding: a short audio cue before bed is re-watched more often than a longer intro.",
|
|
13
|
+
source: "https://research.example/fixture-bedtime-study",
|
|
14
|
+
fetchedOn: "2026-10-04",
|
|
15
|
+
platform: "instagram",
|
|
16
|
+
format: "reel",
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
// Not applied yet: no draft calendar entry exists for it.
|
|
20
|
+
id: "fixture-finding-b",
|
|
21
|
+
topic: "Fixture topic: puddle physics",
|
|
22
|
+
finding: "Fixture finding: a slow reveal of the puddle ripple holds attention past the first seconds.",
|
|
23
|
+
source: "notes/fixture-digest.md:14",
|
|
24
|
+
fetchedOn: "2026-10-04",
|
|
25
|
+
platform: "youtube",
|
|
26
|
+
format: "short",
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
createdAtUtc: "2026-10-05T07:00:00Z",
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
export const FIXTURE_DIGEST_APPLICATIONS = [
|
|
33
|
+
{
|
|
34
|
+
digestId: "fixture-digest-2026-10-05",
|
|
35
|
+
digestEntryId: "fixture-finding-a",
|
|
36
|
+
briefId: "digest_brief.fixture-digest-2026-10-05.fixture-finding-a",
|
|
37
|
+
calendarEntryId: "digest_entry.fixture-digest-2026-10-05.fixture-finding-a",
|
|
38
|
+
appliedAtUtc: "2026-10-05T07:30:00Z",
|
|
39
|
+
},
|
|
40
|
+
];
|