@rizom/ops 0.2.0-alpha.243 → 0.2.0-alpha.245
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/README.md +18 -1
- package/dist/brains-ops.js +290 -142
- package/dist/deploy.js +59 -59
- package/dist/images.d.ts +3 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.js +316 -168
- package/dist/legacy-pilot-migration.d.ts +11 -0
- package/dist/load-registry.d.ts +7 -5
- package/dist/reconcile-dry-run.d.ts +9 -0
- package/dist/schema.d.ts +39 -33
- package/dist/secrets-encrypt.d.ts +2 -0
- package/dist/stage-legacy-crossover.d.ts +20 -0
- package/dist/verify-user.d.ts +1 -1
- package/package.json +3 -2
- package/templates/rover-pilot/.env.schema +7 -0
- package/templates/rover-pilot/.github/workflows/reconcile.yml +5 -5
- package/templates/rover-pilot/README.md +8 -3
- package/templates/rover-pilot/deploy/scripts/decrypt-user-secrets.ts +2 -0
- package/templates/rover-pilot/deploy/scripts/validate-secrets.ts +11 -0
- package/templates/rover-pilot/docs/canonical-crossover-record.md +104 -0
- package/templates/rover-pilot/docs/onboarding-checklist.md +8 -12
- package/templates/rover-pilot/docs/operator-playbook.md +69 -50
- package/templates/rover-pilot/docs/user-onboarding.md +39 -68
- package/templates/rover-pilot/pilot.yaml +2 -3
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type CohortConfig, type PilotConfig } from "./schema";
|
|
2
|
+
/** Offline-only conversion. Active desired-state loading never calls this. */
|
|
3
|
+
export declare function migrateLegacyPilotConfig(input: unknown): PilotConfig;
|
|
4
|
+
/** Offline-only cohort conversion. */
|
|
5
|
+
export declare function migrateLegacyCohortConfig(input: unknown): CohortConfig;
|
|
6
|
+
/** Offline-only YAML rewrite that retains comments while changing the schema. */
|
|
7
|
+
export declare function migrateLegacyPilotYaml(input: string): string;
|
|
8
|
+
/** Offline-only cohort rewrite that retains comments while changing selection. */
|
|
9
|
+
export declare function migrateLegacyCohortYaml(input: string): string;
|
|
10
|
+
export declare function renderPilotConfig(config: PilotConfig): string;
|
|
11
|
+
export declare function renderCohortConfig(config: CohortConfig): string;
|
package/dist/load-registry.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type PilotConfig, type
|
|
1
|
+
import { type PilotConfig, type CanonicalBundleId } from "./schema";
|
|
2
2
|
export type ExternalStatus = "unknown" | "ready" | "failed";
|
|
3
3
|
export type SnapshotStatus = "present" | "missing";
|
|
4
4
|
export interface ObservedUserStatus {
|
|
@@ -11,7 +11,9 @@ export interface ResolvedCohort {
|
|
|
11
11
|
id: string;
|
|
12
12
|
members: string[];
|
|
13
13
|
brainVersionOverride?: string;
|
|
14
|
-
|
|
14
|
+
bundlesOverride?: CanonicalBundleId[];
|
|
15
|
+
addOverride?: string[];
|
|
16
|
+
removeOverride?: string[];
|
|
15
17
|
aiApiKeyOverride?: string;
|
|
16
18
|
gitSyncTokenOverride?: string;
|
|
17
19
|
}
|
|
@@ -74,13 +76,13 @@ export interface ResolvedUserIdentity {
|
|
|
74
76
|
handle: string;
|
|
75
77
|
cohort: string;
|
|
76
78
|
brainVersion: string;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
+
bundles: CanonicalBundleId[];
|
|
80
|
+
add: string[];
|
|
81
|
+
remove: string[];
|
|
79
82
|
domain: string;
|
|
80
83
|
cloudflareZoneId?: string | undefined;
|
|
81
84
|
contentRepo: string;
|
|
82
85
|
profileKind?: string | undefined;
|
|
83
|
-
addOverride?: string[];
|
|
84
86
|
siteOverride?: ResolvedSiteOverride;
|
|
85
87
|
discordEnabled: boolean;
|
|
86
88
|
discordAnchorUserId?: string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface ReconcileDryRunResult {
|
|
2
|
+
firstPassChangedFiles: string[];
|
|
3
|
+
secondPassChangedFiles: string[];
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Reconcile an isolated copy twice with external content-repo access disabled.
|
|
7
|
+
* The source repository is never written.
|
|
8
|
+
*/
|
|
9
|
+
export declare function dryRunReconcileAll(rootDir: string): Promise<ReconcileDryRunResult>;
|
package/dist/schema.d.ts
CHANGED
|
@@ -1,26 +1,46 @@
|
|
|
1
1
|
import { z } from "@brains/utils/zod";
|
|
2
|
-
export declare const presetSchema: z.ZodEnum<{
|
|
3
|
-
core: "core";
|
|
4
|
-
default: "default";
|
|
5
|
-
pro: "pro";
|
|
6
|
-
}>;
|
|
7
2
|
export declare const exactVersionSchema: z.ZodString;
|
|
8
3
|
export declare const handleSchema: z.ZodString;
|
|
9
4
|
export declare const secretNameSchema: z.ZodString;
|
|
10
5
|
export declare const agePublicKeySchema: z.ZodString;
|
|
11
|
-
export declare const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
contentRepoPrefix: z.ZodString;
|
|
17
|
-
domainSuffix: z.ZodString;
|
|
18
|
-
preset: typeof presetSchema;
|
|
19
|
-
aiApiKey: z.ZodString;
|
|
20
|
-
gitSyncToken: z.ZodString;
|
|
21
|
-
contentRepoAdminToken: z.ZodString;
|
|
22
|
-
agePublicKey: z.ZodString;
|
|
6
|
+
export declare const canonicalBundleIdSchema: z.ZodEnum<{
|
|
7
|
+
core: "core";
|
|
8
|
+
site: "site";
|
|
9
|
+
publishing: "publishing";
|
|
10
|
+
team: "team";
|
|
23
11
|
}>;
|
|
12
|
+
export type CanonicalBundleId = z.output<typeof canonicalBundleIdSchema>;
|
|
13
|
+
export interface PilotConfig {
|
|
14
|
+
brainVersion: string;
|
|
15
|
+
bundles: CanonicalBundleId[];
|
|
16
|
+
add?: string[] | undefined;
|
|
17
|
+
remove?: string[] | undefined;
|
|
18
|
+
githubOrg: string;
|
|
19
|
+
contentRepoPrefix: string;
|
|
20
|
+
domainSuffix: string;
|
|
21
|
+
aiApiKey: string;
|
|
22
|
+
gitSyncToken: string;
|
|
23
|
+
contentRepoAdminToken: string;
|
|
24
|
+
agePublicKey: string;
|
|
25
|
+
}
|
|
26
|
+
export interface SiteOverrideConfig {
|
|
27
|
+
package: string;
|
|
28
|
+
version: string;
|
|
29
|
+
theme?: string | undefined;
|
|
30
|
+
themeVersion?: string | undefined;
|
|
31
|
+
}
|
|
32
|
+
export interface CohortConfig {
|
|
33
|
+
members: string[];
|
|
34
|
+
brainVersionOverride?: string | undefined;
|
|
35
|
+
bundlesOverride?: CanonicalBundleId[] | undefined;
|
|
36
|
+
addOverride?: string[] | undefined;
|
|
37
|
+
removeOverride?: string[] | undefined;
|
|
38
|
+
aiApiKeyOverride?: string | undefined;
|
|
39
|
+
gitSyncTokenOverride?: string | undefined;
|
|
40
|
+
}
|
|
41
|
+
/** Sole active desired-state contract for the canonical brain. */
|
|
42
|
+
export declare const pilotSchema: z.ZodType<PilotConfig>;
|
|
43
|
+
export declare const cohortSchema: z.ZodType<CohortConfig>;
|
|
24
44
|
declare const anchorProfileSocialLinkSchema: z.ZodObject<{
|
|
25
45
|
platform: z.ZodEnum<{
|
|
26
46
|
github: "github";
|
|
@@ -70,12 +90,7 @@ declare const atprotoSchema: z.ZodObject<{
|
|
|
70
90
|
lexiconAuthority: z.ZodOptional<z.ZodBoolean>;
|
|
71
91
|
jetstream: z.ZodOptional<typeof atprotoJetstreamSchema>;
|
|
72
92
|
}>;
|
|
73
|
-
declare const siteOverrideSchema: z.
|
|
74
|
-
package: z.ZodString;
|
|
75
|
-
version: z.ZodOptional<typeof exactVersionSchema>;
|
|
76
|
-
theme: z.ZodOptional<z.ZodString>;
|
|
77
|
-
themeVersion: z.ZodOptional<typeof exactVersionSchema>;
|
|
78
|
-
}>;
|
|
93
|
+
export declare const siteOverrideSchema: z.ZodType<SiteOverrideConfig>;
|
|
79
94
|
declare const playbooksSchema: z.ZodObject<{
|
|
80
95
|
onboarding: z.ZodOptional<z.ZodBoolean>;
|
|
81
96
|
}>;
|
|
@@ -92,24 +107,15 @@ export declare const userSchema: z.ZodObject<{
|
|
|
92
107
|
contentRepoOverride: z.ZodOptional<z.ZodString>;
|
|
93
108
|
profileKind: z.ZodOptional<z.ZodString>;
|
|
94
109
|
addOverride: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
110
|
+
removeOverride: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
95
111
|
siteOverride: z.ZodOptional<typeof siteOverrideSchema>;
|
|
96
112
|
setup: z.ZodOptional<typeof setupDeliverySchema>;
|
|
97
113
|
atproto: z.ZodOptional<typeof atprotoSchema>;
|
|
98
114
|
playbooks: z.ZodOptional<typeof playbooksSchema>;
|
|
99
115
|
anchorProfile: z.ZodOptional<typeof anchorProfileSchema>;
|
|
100
116
|
}>;
|
|
101
|
-
export declare const cohortSchema: z.ZodObject<{
|
|
102
|
-
members: z.ZodArray<z.ZodString>;
|
|
103
|
-
brainVersionOverride: z.ZodOptional<z.ZodString>;
|
|
104
|
-
presetOverride: z.ZodOptional<typeof presetSchema>;
|
|
105
|
-
aiApiKeyOverride: z.ZodOptional<z.ZodString>;
|
|
106
|
-
gitSyncTokenOverride: z.ZodOptional<z.ZodString>;
|
|
107
|
-
}>;
|
|
108
|
-
export type PilotConfig = z.output<typeof pilotSchema>;
|
|
109
117
|
export type PilotConfigInput = z.input<typeof pilotSchema>;
|
|
110
118
|
export type UserConfig = z.output<typeof userSchema>;
|
|
111
119
|
export type UserConfigInput = z.input<typeof userSchema>;
|
|
112
|
-
export type CohortConfig = z.output<typeof cohortSchema>;
|
|
113
120
|
export type CohortConfigInput = z.input<typeof cohortSchema>;
|
|
114
|
-
export type PilotPreset = z.output<typeof presetSchema>;
|
|
115
121
|
export {};
|
|
@@ -2,6 +2,8 @@ import { z } from "@brains/utils/zod";
|
|
|
2
2
|
declare const encryptedUserSecretsSchema: z.ZodObject<{
|
|
3
3
|
gitSyncToken: z.ZodOptional<z.ZodString>;
|
|
4
4
|
discordBotToken: z.ZodOptional<z.ZodString>;
|
|
5
|
+
discordPublicKey: z.ZodOptional<z.ZodString>;
|
|
6
|
+
discordApplicationId: z.ZodOptional<z.ZodString>;
|
|
5
7
|
aiApiKey: z.ZodOptional<z.ZodString>;
|
|
6
8
|
atprotoAppPassword: z.ZodOptional<z.ZodString>;
|
|
7
9
|
certificatePem: z.ZodOptional<z.ZodString>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type SiteOverrideConfig } from "./schema";
|
|
2
|
+
export interface StagedCrossover {
|
|
3
|
+
outputDir: string;
|
|
4
|
+
changedFiles: string[];
|
|
5
|
+
}
|
|
6
|
+
interface ReviewedSitePinManifest {
|
|
7
|
+
sites: Record<string, SiteOverrideConfig>;
|
|
8
|
+
}
|
|
9
|
+
export type ReviewedSitePins = ReviewedSitePinManifest["sites"];
|
|
10
|
+
export interface StageLegacyCrossoverOptions {
|
|
11
|
+
sitePins?: ReviewedSitePins | undefined;
|
|
12
|
+
}
|
|
13
|
+
export declare function parseReviewedSitePins(input: string): ReviewedSitePins;
|
|
14
|
+
export declare function loadReviewedSitePins(filePath: string): Promise<ReviewedSitePins>;
|
|
15
|
+
/**
|
|
16
|
+
* Build a complete review copy without mutating the source repository.
|
|
17
|
+
* This is offline migration tooling; active desired-state loading is canonical-only.
|
|
18
|
+
*/
|
|
19
|
+
export declare function stageLegacyCrossover(sourceDir: string, outputDir: string, options?: StageLegacyCrossoverOptions): Promise<StagedCrossover>;
|
|
20
|
+
export {};
|
package/dist/verify-user.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rizom/ops",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.245",
|
|
4
4
|
"description": "Operator CLI for managing private brain fleet registry repos",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"brains",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
},
|
|
18
18
|
"bugs": "https://github.com/rizom-ai/brains/issues",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"age-encryption": "^0.3.0"
|
|
20
|
+
"age-encryption": "^0.3.0",
|
|
21
|
+
"yaml": "^2.9.0"
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
23
24
|
"@brains/deploy-support": "workspace:*",
|
|
@@ -25,6 +25,13 @@ CONTENT_REPO_ADMIN_TOKEN=
|
|
|
25
25
|
# @sensitive
|
|
26
26
|
DISCORD_BOT_TOKEN=
|
|
27
27
|
|
|
28
|
+
# Stored with the per-user Discord credentials and injected at deploy time.
|
|
29
|
+
# @sensitive
|
|
30
|
+
DISCORD_PUBLIC_KEY=
|
|
31
|
+
|
|
32
|
+
# @sensitive
|
|
33
|
+
DISCORD_APPLICATION_ID=
|
|
34
|
+
|
|
28
35
|
# AT Protocol publishing/discovery (optional, per-user)
|
|
29
36
|
# Comes from the decrypted users/<handle>.secrets.yaml.age file when configured.
|
|
30
37
|
# @sensitive
|
|
@@ -39,23 +39,23 @@ jobs:
|
|
|
39
39
|
# `git diff` cannot see untracked files — without intent-to-add
|
|
40
40
|
# the new config is silently dropped here and every later deploy
|
|
41
41
|
# skips that user (their files never appear in a commit range).
|
|
42
|
-
git add --intent-to-add --
|
|
42
|
+
git add --intent-to-add -- users
|
|
43
43
|
|
|
44
|
-
if git diff --quiet --
|
|
44
|
+
if git diff --quiet -- users; then
|
|
45
45
|
exit 0
|
|
46
46
|
fi
|
|
47
47
|
|
|
48
48
|
git fetch origin "${{ github.ref_name }}"
|
|
49
|
-
if git diff --quiet "origin/${{ github.ref_name }}" --
|
|
49
|
+
if git diff --quiet "origin/${{ github.ref_name }}" -- users; then
|
|
50
50
|
exit 0
|
|
51
51
|
fi
|
|
52
52
|
|
|
53
53
|
patch_file="$(mktemp)"
|
|
54
|
-
git diff --binary --
|
|
54
|
+
git diff --binary -- users > "$patch_file"
|
|
55
55
|
git reset --hard "origin/${{ github.ref_name }}"
|
|
56
56
|
git apply --3way --index "$patch_file"
|
|
57
57
|
|
|
58
|
-
if git diff --cached --quiet --
|
|
58
|
+
if git diff --cached --quiet -- users; then
|
|
59
59
|
exit 0
|
|
60
60
|
fi
|
|
61
61
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
#
|
|
1
|
+
# private brain pilot
|
|
2
2
|
|
|
3
|
-
Private desired-state
|
|
3
|
+
Private desired-state repository for the hosted brain pilot. The generated repository/service name may remain `rover-pilot` for deployment identity compatibility.
|
|
4
4
|
|
|
5
5
|
This is a single operator-owned repo. Pilot users do not get their own brain repos.
|
|
6
6
|
Per-user deploy config lives under `users/<handle>/`, while content stays in per-user content repos.
|
|
@@ -31,7 +31,7 @@ The repo also checks in its deploy contract:
|
|
|
31
31
|
`.env.schema` is the single source of truth for required and sensitive deploy vars.
|
|
32
32
|
Use separate GitHub tokens: `CONTENT_REPO_ADMIN_TOKEN` for operator-side content repo creation/checks, and `GIT_SYNC_TOKEN` for runtime directory-sync git access.
|
|
33
33
|
The default pilot image tag is `brain-${brainVersion}` end to end. A user with `siteOverride` gets an isolated `brain-${brainVersion}-sites-${packageHash}` image instead.
|
|
34
|
-
When the effective brain version (`pilot.yaml.brainVersion`, or a cohort override) changes and you push, CI rebuilds the required default/site tags, refreshes generated user env files, and redeploys affected users.
|
|
34
|
+
When the effective brain version (`pilot.yaml.brainVersion`, or a cohort override) changes and you push, CI rebuilds the required default/site tags, refreshes generated user env files, and redeploys affected users. Every external site and theme package uses its own required exact version pin; ops never infers either version from the brain or from another package.
|
|
35
35
|
When a push changes only deploy contract files, CI prints `No affected user configs; skipping deploy.` and stops before Kamal.
|
|
36
36
|
|
|
37
37
|
## Commands
|
|
@@ -46,3 +46,8 @@ When a push changes only deploy contract files, CI prints `No affected user conf
|
|
|
46
46
|
- `brains-ops secrets:encrypt <repo> <handle>`
|
|
47
47
|
- `brains-ops reconcile-cohort <repo> <cohort>`
|
|
48
48
|
- `brains-ops reconcile-all <repo>`
|
|
49
|
+
- `brains-ops reconcile-all <repo> --dry-run` (isolated, no external content-repository access; lists both passes' changed files)
|
|
50
|
+
|
|
51
|
+
`render` owns the observational `views/users.md` projection. Reconcile owns generated per-user config and never rewrites observed status rows.
|
|
52
|
+
|
|
53
|
+
Use `docs/canonical-crossover-record.md` to record exact forward and rollback artifact pins before an approved crossover window.
|
|
@@ -25,6 +25,8 @@ writeSecretGitHubEnv(
|
|
|
25
25
|
secrets["cmsContentRepoPat"] ?? secrets["gitSyncToken"],
|
|
26
26
|
);
|
|
27
27
|
writeSecretGitHubEnv("DISCORD_BOT_TOKEN", secrets["discordBotToken"]);
|
|
28
|
+
writeSecretGitHubEnv("DISCORD_PUBLIC_KEY", secrets["discordPublicKey"]);
|
|
29
|
+
writeSecretGitHubEnv("DISCORD_APPLICATION_ID", secrets["discordApplicationId"]);
|
|
28
30
|
// Per-user AT Protocol publishing credential (optional; from the user's
|
|
29
31
|
// encrypted secrets file). The scaffold wires this so a pilot can publish its
|
|
30
32
|
// brain's agent card to its PDS; a deployment that doesn't publish simply
|
|
@@ -14,6 +14,17 @@ for (const key of requiredKeys) {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
const discordKeys = [
|
|
18
|
+
"DISCORD_BOT_TOKEN",
|
|
19
|
+
"DISCORD_PUBLIC_KEY",
|
|
20
|
+
"DISCORD_APPLICATION_ID",
|
|
21
|
+
];
|
|
22
|
+
if (discordKeys.some((key) => process.env[key])) {
|
|
23
|
+
for (const key of discordKeys) {
|
|
24
|
+
if (!process.env[key]) missing.push(key);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
17
28
|
if (missing.length > 0) {
|
|
18
29
|
throw new Error(`Missing required secrets: ${missing.join(", ")}`);
|
|
19
30
|
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Canonical Crossover Approval Record
|
|
2
|
+
|
|
3
|
+
> Draft evidence record only. Completing this file does not authorize a merge, publish, reconcile, or deployment.
|
|
4
|
+
|
|
5
|
+
Do not include secret values, private keys, access tokens, or decrypted user configuration.
|
|
6
|
+
|
|
7
|
+
## Authorization and freeze
|
|
8
|
+
|
|
9
|
+
- Operator:
|
|
10
|
+
- Approval reference:
|
|
11
|
+
- Approved window:
|
|
12
|
+
- Freeze start:
|
|
13
|
+
- Build workflow disabled and idle:
|
|
14
|
+
- Reconcile workflow disabled and idle:
|
|
15
|
+
- Deploy workflow disabled and idle:
|
|
16
|
+
|
|
17
|
+
## Reviewed inputs
|
|
18
|
+
|
|
19
|
+
- `brains` crossover commit:
|
|
20
|
+
- Private-pilot source commit used for staging:
|
|
21
|
+
- Canonical review commit:
|
|
22
|
+
- Secret-free review diff SHA-256:
|
|
23
|
+
- Identity-review evidence SHA-256:
|
|
24
|
+
- Reviewed hosted-site pin manifest SHA-256:
|
|
25
|
+
- Source and review worktrees clean:
|
|
26
|
+
|
|
27
|
+
## Hosted site and theme pins
|
|
28
|
+
|
|
29
|
+
List every hosted site. External site and theme package versions must be exact and must
|
|
30
|
+
match the staged user desired state; do not infer them from the brain or from each other.
|
|
31
|
+
|
|
32
|
+
| Handle | Site package | Exact site version | Theme package | Exact theme version | Package/image evidence |
|
|
33
|
+
| ------ | ------------ | ------------------ | ------------- | ------------------- | ---------------------- |
|
|
34
|
+
| | | | | | |
|
|
35
|
+
|
|
36
|
+
## Forward artifact pins
|
|
37
|
+
|
|
38
|
+
| Artifact | Exact version | Registry integrity or digest | Verified installable |
|
|
39
|
+
| ---------------------- | ------------- | ---------------------------- | -------------------- |
|
|
40
|
+
| `@rizom/brain` | | | |
|
|
41
|
+
| `@rizom/ops` | | | |
|
|
42
|
+
| private-pilot lockfile | n/a | | |
|
|
43
|
+
|
|
44
|
+
Record every image. Tags alone are not immutable evidence.
|
|
45
|
+
|
|
46
|
+
| Cohort/handle | Config commit | Image repository | Image tag | Image digest |
|
|
47
|
+
| ------------- | ------------- | ---------------- | --------- | ------------ |
|
|
48
|
+
| | | | | |
|
|
49
|
+
|
|
50
|
+
## Rollback pair
|
|
51
|
+
|
|
52
|
+
- Prior private-pilot commit:
|
|
53
|
+
- Prior `@rizom/ops` version and registry integrity:
|
|
54
|
+
|
|
55
|
+
| Cohort/handle | Prior config commit | Prior image repository | Prior image tag | Prior image digest |
|
|
56
|
+
| ------------- | ------------------- | ---------------------- | --------------- | ------------------ |
|
|
57
|
+
| | | | | |
|
|
58
|
+
|
|
59
|
+
## Identity review
|
|
60
|
+
|
|
61
|
+
- Repository and image names unchanged or explicitly approved:
|
|
62
|
+
- GitHub organization and content repository identities unchanged:
|
|
63
|
+
- Server, domain, Cloudflare zone, and ATProto identities unchanged:
|
|
64
|
+
- Secret selector names and encrypted secret artifacts unchanged:
|
|
65
|
+
- Per-user runtime-version and site-package tag inputs reviewed:
|
|
66
|
+
- No plaintext source secrets copied into the review artifact:
|
|
67
|
+
- No removed model, preset, or old-format schema discriminator remains:
|
|
68
|
+
- Every external hosted site and theme package has an exact reviewed pin:
|
|
69
|
+
|
|
70
|
+
## Offline convergence
|
|
71
|
+
|
|
72
|
+
Command:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
bunx brains-ops reconcile-all <canonical-review-copy> --dry-run
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
- First-pass reconciler-owned changed files:
|
|
79
|
+
- Second-pass reconciler-owned changed files (must be zero):
|
|
80
|
+
- Observational `views/users.md` unchanged by reconciliation:
|
|
81
|
+
- Review copy unchanged:
|
|
82
|
+
- External content-repository access blocked:
|
|
83
|
+
|
|
84
|
+
## Pre-window validation
|
|
85
|
+
|
|
86
|
+
- Package tests, typecheck, lint, build, and packed-consumer startup:
|
|
87
|
+
- Architecture and dependency boundaries:
|
|
88
|
+
- Environment-schema and workspace checks:
|
|
89
|
+
- Crossover migration and comment preservation:
|
|
90
|
+
- Canary-first order and health checks reviewed:
|
|
91
|
+
- Paired rollback reviewed:
|
|
92
|
+
|
|
93
|
+
## Execution record
|
|
94
|
+
|
|
95
|
+
Complete only inside the explicitly approved maintenance window.
|
|
96
|
+
|
|
97
|
+
- Unified packages published and verified:
|
|
98
|
+
- Canonical desired state committed while automation remained frozen:
|
|
99
|
+
- Image digest set matched this record:
|
|
100
|
+
- First reconcile reviewed:
|
|
101
|
+
- Per-instance health, MCP authorization, identity, content, and site checks:
|
|
102
|
+
- Second reconcile produced zero reconciler-owned drift and no deploy work:
|
|
103
|
+
- Freeze lifted:
|
|
104
|
+
- One-week soak start:
|
|
@@ -23,18 +23,14 @@
|
|
|
23
23
|
10. Run `bunx brains-ops secrets:encrypt <repo> <handle>`.
|
|
24
24
|
11. Commit and push `users/<handle>.secrets.yaml.age`.
|
|
25
25
|
12. Run `bunx brains-ops onboard <repo> <handle>`.
|
|
26
|
-
13. Verify the deployed
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
- background jobs are not repeatedly failing, except for expected missing optional integrations
|
|
35
|
-
- for `presetOverride: default` users:
|
|
36
|
-
- initial site build completes
|
|
37
|
-
14. For fleet upgrades, edit `pilot.yaml.brainVersion` and push once; CI rebuilds the required default/site image tags, refreshes generated user env files, and redeploys affected users. Site overrides follow the user's effective brain version unless they declare an explicit exact `version` pin.
|
|
26
|
+
13. Verify the deployed canonical contract:
|
|
27
|
+
- `https://<handle>.rizom.ai/health` returns `200`
|
|
28
|
+
- `https://<handle>.rizom.ai/chat` loads the web chat and accepts passkey sign-in
|
|
29
|
+
- unauthenticated `POST https://<handle>.rizom.ai/mcp` returns the expected auth failure
|
|
30
|
+
- content repo exists and runtime sync is healthy
|
|
31
|
+
- background jobs are not repeatedly failing, except for expected missing optional integrations
|
|
32
|
+
- when `site` is selected, the browser/CMS surfaces load and the initial app-managed site build completes
|
|
33
|
+
14. For fleet upgrades, edit `pilot.yaml.brainVersion` and push once; CI rebuilds the required default/site image tags, refreshes generated user env files, and redeploys affected users. Every external site and theme package keeps its own required exact version pin and never follows the brain version implicitly.
|
|
38
34
|
15. Confirm the user received the setup email, registered their passkey, and can sign in to web chat at `https://<handle>.rizom.ai/chat`. That completes the default onboarding; everything below is per-cohort extras.
|
|
39
35
|
16. Hand over the browser surfaces:
|
|
40
36
|
- Chat (primary): `https://<handle>.rizom.ai/chat`
|