@bongos/core 1.19.1072 → 1.19.1074
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/.bongos-core.json +320 -465
- package/.claude/skills/feedback/SKILL.md +2 -2
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +4 -60
- package/clients/bongos-client/index.cjs +4 -60
- package/clients/bongos-client/index.d.ts +5 -90
- package/clients/bongos-client/index.mjs +4 -60
- package/config/branding.neutral.json +1 -5
- package/config/modules.neutral.json +2 -3
- package/config/scheduled-routines.json +0 -2
- package/docs/adr/0145-free-hosted-project-tier-isolation-and-domain-separation.md +1 -0
- package/docs/adr/0285-a-shared-box-holds-about-twelve-projects-per-gb-and-memory-is-the-wall.md +1 -0
- package/docs/adr/0323-hosting-is-three-shapes-and-we-are-not-the-landlord.md +1 -1
- package/docs/adr/0327-a-cloud-host-runs-on-the-owners-account-and-the-key-is-borrowed.md +1 -1
- package/docs/adr/0341-the-page-is-the-unit-of-tweak-mode.md +6 -2
- package/docs/adr/0345-we-host-every-projects-hall-and-its-app-deploys-where-the-owner-chooses.md +94 -0
- package/docs/adr/README.md +2 -1
- package/docs/api/openapi.json +171 -1661
- package/docs/api-reference.md +9 -41
- package/docs/architecture.md +16 -1
- package/docs/branding-contract.md +0 -3
- package/docs/copy-inventory.md +454 -479
- package/docs/copy-registry.json +746 -978
- package/docs/file-map.md +5 -34
- package/docs/module-api-changelog.md +4 -0
- package/docs/modules-contract.md +13 -1
- package/docs/onboarding/diagrams/04-architecture.mmd +11 -22
- package/docs/onboarding/diagrams/README.md +3 -3
- package/docs/onboarding/diagrams/assertions.json +2 -22
- package/docs/onboarding/primer.md +9 -28
- package/docs/page-inventory.json +4 -1
- package/docs/page-readings.json +1032 -1077
- package/docs/recipes/render-pilot.md +29 -10
- package/migrations/core_257_module_store_registry.sql +87 -0
- package/migrations/core_258_drop_dev_box_tables.sql +55 -0
- package/modules/agents/module.json +1 -0
- package/modules/autonomy/module.json +1 -0
- package/modules/builder-settings/module.json +1 -0
- package/modules/builder-settings/render-prefs.js +4 -5
- package/modules/copy-desk/docx.js +78 -5
- package/modules/copy-desk/module.json +1 -0
- package/modules/copy-desk/routes/copy-desk.js +9 -9
- package/modules/copy-desk/tests/copy_docx.mjs +107 -1
- package/modules/copy-desk/tests/fixtures/word-docx.mjs +30 -0
- package/modules/discord/module.json +1 -0
- package/modules/economy/module.json +1 -0
- package/modules/economy/routes/credits.js +1 -2
- package/modules/government/catalog.js +13 -17
- package/modules/government/migrations/government_019_retire_box_permissions.sql +33 -0
- package/modules/government/module.json +1 -0
- package/modules/government/protected-surfaces.json +3 -11
- package/modules/government/resolver.js +3 -46
- package/modules/government/routes/government.js +0 -2
- package/modules/government/session-scopes.js +43 -83
- package/modules/government/session-scopes.json +8 -18
- package/modules/grading/module.json +1 -0
- package/modules/hall-ui/module.json +1 -0
- package/modules/hall-ui/public/board-lib.js +2 -2
- package/modules/hall-ui/public/builders.js +29 -40
- package/modules/hall-ui/public/collab.html +1 -1
- package/modules/hall-ui/public/collab.js +1 -1
- package/modules/hall-ui/public/diagrams.html +3 -3
- package/modules/hall-ui/public/dom-utils.js +1 -1
- package/modules/hall-ui/public/gate.js +2 -2
- package/modules/hall-ui/public/gate.states.json +1 -1
- package/modules/hall-ui/public/hall-render.js +43 -79
- package/modules/hall-ui/public/index.html +5 -1
- package/modules/hall-ui/public/modules.js +1 -0
- package/modules/hall-ui/public/oversight.css +5 -5
- package/modules/hall-ui/public/palette.js +0 -11
- package/modules/hall-ui/public/primer.js +1 -1
- package/modules/hall-ui/public/sessions.html +1 -1
- package/modules/hall-ui/public/settings-sessions.js +1 -1
- package/modules/hall-ui/public/settings.css +0 -1
- package/modules/hall-ui/public/settings.html +4 -33
- package/modules/hall-ui/public/settings.js +3 -33
- package/modules/hall-ui/public/settings.states.json +2 -2
- package/modules/hall-ui/public/studio.html +1 -1
- package/modules/hall-ui/public/style.css +10 -13
- package/modules/hall-ui/public/task.html +4 -1
- package/modules/hall-ui/public/task.js +36 -1
- package/modules/hall-ui/public/tweak-editor-lib.js +18 -1
- package/modules/hall-ui/public/tweak-editor.css +16 -0
- package/modules/hall-ui/public/tweak-editor.html +26 -3
- package/modules/hall-ui/public/tweak-editor.js +32 -1
- package/modules/hall-ui/public/work.js +1 -1
- package/modules/hall-ui/records/tweak-editor.md +1 -0
- package/modules/ideas/module.json +1 -0
- package/modules/lifecycle/db-claim-reads.js +1 -58
- package/modules/lifecycle/db-ship.js +0 -5
- package/modules/lifecycle/db.js +0 -4
- package/modules/lifecycle/kickoff-checklist.js +0 -4
- package/modules/lifecycle/lifecycle.js +0 -8
- package/modules/lifecycle/module.json +1 -0
- package/modules/lifecycle/routes/tasks.js +5 -7
- package/modules/memory/module.json +1 -0
- package/modules/npm-release/module.json +1 -0
- package/modules/onboarding/module.json +1 -0
- package/modules/onboarding/onboarding-state.js +17 -36
- package/modules/onboarding/routes/access-requests.js +3 -3
- package/modules/platform-identity/module.json +1 -0
- package/modules/platform-identity/platform-identity.js +13 -5
- package/modules/platform-identity/routes/sso.js +2 -2
- package/modules/platform-identity/tests/platform-identity.mjs +17 -3
- package/modules/provisioning/module.json +1 -0
- package/modules/provisioning/provisioning.js +2 -2
- package/modules/provisioning/starter-bundles.js +5 -25
- package/modules/public-landing/module.json +1 -0
- package/modules/public-landing/public/assets/cosmos.css +1 -1
- package/modules/public-landing/public/contact.html +1 -1
- package/modules/public-landing/public/privacy.html +1 -1
- package/modules/public-landing/public/projects.html +101 -32
- package/modules/public-landing/public/projects.probes.json +2 -2
- package/modules/public-landing/public/projects.states.json +4 -3
- package/modules/public-landing/public/terms.html +1 -1
- package/modules/security/module.json +1 -0
- package/modules/sessions/module.json +1 -0
- package/modules/specialities/module.json +1 -0
- package/modules/status-ui/module.json +1 -0
- package/modules/ui-design/module.json +1 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +84 -0
- package/scripts/gds/artifact-format.js +203 -0
- package/scripts/gds/audit-authorship.sh +1 -13
- package/scripts/gds/claim.js +0 -15
- package/scripts/gds/cli-lib.js +8 -8
- package/scripts/gds/diagram-facts.js +12 -23
- package/scripts/gds/do-api.js +13 -80
- package/scripts/gds/doc-cli-guard.js +2 -0
- package/scripts/gds/doctor.js +1 -1
- package/scripts/gds/feedback-latest.js +139 -9
- package/scripts/gds/fitness-checks-identity.js +2 -7
- package/scripts/gds/fitness-checks-write-validation.js +4 -0
- package/scripts/gds/fitness-ratchets.js +4 -4
- package/scripts/gds/fitness.js +10 -10
- package/scripts/gds/gen-diagrams.js +49 -71
- package/scripts/gds/http-api-client.js +12 -19
- package/scripts/gds/init.js +1 -1
- package/scripts/gds/lint-infra-exec.js +1 -1
- package/scripts/gds/local-preview-lib.js +8 -39
- package/scripts/gds/local-preview.js +2 -15
- package/scripts/gds/migration-namespace.js +3 -3
- package/scripts/gds/module-artifact.js +212 -0
- package/scripts/gds/module.js +95 -6
- package/scripts/gds/package-core.js +5 -116
- package/scripts/gds/provision-config.js +2 -2
- package/scripts/gds/provision-net.js +2 -3
- package/scripts/gds/provision.js +9 -9
- package/scripts/gds/publish-manifest.js +1 -2
- package/scripts/gds/regen-instance-docs.js +1 -1
- package/scripts/gds/run-unit-tests.js +2 -16
- package/scripts/gds/sandbox-stage.js +39 -341
- package/scripts/gds/ship-flow.js +6 -6
- package/scripts/gds/ship-land.js +3 -4
- package/scripts/gds/ship-regen.js +10 -41
- package/scripts/gds/ship.js +4 -24
- package/scripts/gds/start.js +0 -15
- package/scripts/hall-preview/README.md +5 -5
- package/scripts/hall-preview/server.js +6 -6
- package/scripts/render-diagrams.sh +1 -1
- package/src/bongos/api-errors.js +1 -1
- package/src/bongos/auth-github.js +2 -3
- package/src/bongos/auth.js +51 -126
- package/src/bongos/db-kernel.js +2 -3
- package/src/bongos/db.js +5 -28
- package/src/bongos/module-scope-map.js +14 -29
- package/src/bongos/module-store.js +141 -0
- package/src/bongos/route-rank-check.js +3 -16
- package/src/bongos/routes/auth.js +0 -116
- package/src/bongos/routes/builders.js +5 -15
- package/src/bongos/routes/instance.js +8 -14
- package/src/bongos/routes/me.js +6 -22
- package/src/bongos/routes/modules.js +83 -0
- package/src/bongos/routes.js +5 -0
- package/src/module-api.js +13 -6
- package/src/module-loader/catalog.js +3 -0
- package/src/module-loader/loader.js +4 -4
- package/src/module-loader/manifest-schema.js +15 -7
- package/src/module-seams.js +2 -3
- package/src/modules.js +42 -14
- package/tests/agents_spend_guard.mjs +1 -1
- package/tests/api_client.mjs +0 -15
- package/tests/auth_page_gate.mjs +10 -10
- package/tests/canonical_profile_url.mjs +1 -3
- package/tests/claim_action.mjs +4 -1
- package/tests/claim_from_task_and_home.mjs +127 -0
- package/tests/consumer_layout_boot.mjs +2 -0
- package/tests/copy_desk_page_docx.mjs +33 -2
- package/tests/core_upgrade_runner.mjs +6 -6
- package/tests/deploy_divergence_line.mjs +11 -11
- package/tests/diagram_facts_offset.mjs +1 -1
- package/tests/do_api.mjs +106 -0
- package/tests/feedback_latest.mjs +122 -0
- package/tests/fitness.mjs +44 -42
- package/tests/gate_approvals.mjs +0 -1
- package/tests/go_live.mjs +3 -3
- package/tests/government_abuse_matrix.mjs +20 -19
- package/tests/government_ownership_scope.mjs +33 -35
- package/tests/government_parity.mjs +2 -2
- package/tests/government_protected_surfaces.mjs +56 -37
- package/tests/government_require_permission.mjs +3 -3
- package/tests/government_seed.mjs +37 -4
- package/tests/government_session_scope.mjs +92 -366
- package/tests/hall_error_envelope.mjs +4 -0
- package/tests/hall_landing_boot.mjs +4 -1
- package/tests/hall_palette.mjs +1 -16
- package/tests/hall_record_world.mjs +6 -0
- package/tests/hall_tweak_editor.mjs +52 -1
- package/tests/host_topology_skips.mjs +1 -2
- package/tests/html_comment_nesting.mjs +137 -0
- package/tests/infra_exec_paths.mjs +9 -10
- package/tests/init.mjs +4 -5
- package/tests/instance_manifest.mjs +18 -25
- package/tests/kickoff_checklist.mjs +1 -1
- package/tests/lib_sh_resolution.mjs +0 -221
- package/tests/local_preview.mjs +0 -12
- package/tests/module-scope-map.mjs +9 -9
- package/tests/module_catalog.mjs +1 -1
- package/tests/module_cli.mjs +15 -15
- package/tests/module_contributions.mjs +6 -6
- package/tests/module_loader.mjs +6 -6
- package/tests/module_manifest.mjs +13 -4
- package/tests/module_store_publish.mjs +307 -0
- package/tests/module_store_publish_route.mjs +121 -0
- package/tests/module_store_registry_migration.mjs +70 -0
- package/tests/modules.mjs +56 -26
- package/tests/onboarding_route_signals.mjs +21 -31
- package/tests/onboarding_state.mjs +35 -49
- package/tests/permission_path.mjs +0 -3
- package/tests/platform_boot.mjs +1 -2
- package/tests/profile_route.mjs +1 -6
- package/tests/projects_hub.mjs +5 -5
- package/tests/projects_hub_app_step.mjs +138 -0
- package/tests/projects_hub_module_picker.mjs +2 -2
- package/tests/projects_hub_pre_uat.mjs +4 -5
- package/tests/provision.mjs +7 -7
- package/tests/provisioning_starter_bundles.mjs +0 -22
- package/tests/publish_branch_route.mjs +10 -18
- package/tests/publish_manifest.mjs +1 -2
- package/tests/rank_tier_single_source.mjs +1 -13
- package/tests/repo_map.mjs +3 -4
- package/tests/runner_drift.mjs +3 -21
- package/tests/sandbox_stage.mjs +57 -390
- package/tests/session_rename_fallback.mjs +0 -21
- package/tests/ship_error_shape.mjs +1 -1
- package/tests/task_visual_slots.mjs +31 -0
- package/tests/terms_acceptance.mjs +1 -1
- package/tests/upgrade.mjs +4 -4
- package/tests/watch_sealed_floor.mjs +0 -1
- package/tests/wizard_draft_resume.mjs +2 -2
- package/tests/wizard_intent_resume.mjs +21 -10
- package/tests/wizard_preselect_why.mjs +18 -18
- package/docs/onboarding/browser-terminal-guide.md +0 -73
- package/docs/recipes/managed-settings-remote-control.md +0 -416
- package/modules/dev-box/CLAUDE.md +0 -15
- package/modules/dev-box/box-access.js +0 -623
- package/modules/dev-box/box-credential.js +0 -94
- package/modules/dev-box/box-onboard.js +0 -486
- package/modules/dev-box/boxes.js +0 -1038
- package/modules/dev-box/db.js +0 -39
- package/modules/dev-box/module.json +0 -19
- package/modules/dev-box/routes/box.js +0 -1223
- package/scripts/gds/box-auth-check.js +0 -160
- package/scripts/gds/box-infra.js +0 -321
- package/scripts/gds/box-sync.js +0 -216
- package/scripts/gds/box.js +0 -1332
- package/scripts/gds/cf-tunnel.js +0 -558
- package/scripts/gds/smoke-box.sh +0 -150
- package/scripts/gds/tree-preflight.js +0 -241
- package/src/bongos/app-pair.js +0 -172
- package/tests/app_pair.mjs +0 -168
- package/tests/box_access.mjs +0 -578
- package/tests/box_auth_check.mjs +0 -114
- package/tests/box_code_staleness.mjs +0 -129
- package/tests/box_connect_e2e.mjs +0 -196
- package/tests/box_cost.mjs +0 -70
- package/tests/box_credential.mjs +0 -125
- package/tests/box_dns_repoint.mjs +0 -153
- package/tests/box_env.mjs +0 -64
- package/tests/box_host_keys.mjs +0 -126
- package/tests/box_infra_resolve.mjs +0 -246
- package/tests/box_onboard.mjs +0 -317
- package/tests/box_scope_session.mjs +0 -119
- package/tests/box_sweep_docs.mjs +0 -119
- package/tests/box_sync.mjs +0 -55
- package/tests/box_sync_scope_report.mjs +0 -126
- package/tests/box_task_scope.mjs +0 -169
- package/tests/box_task_scope_pause.mjs +0 -66
- package/tests/box_terminal_ssrf.mjs +0 -96
- package/tests/boxes.mjs +0 -1585
- package/tests/cf_ruleset_preflight.mjs +0 -142
- package/tests/cf_tunnel.mjs +0 -496
- package/tests/docs_scrubber_damage.mjs +0 -111
- package/tests/module_scope_active_claims.mjs +0 -94
- package/tests/ship_api_client_pathspec.mjs +0 -100
- package/tests/tree_preflight.mjs +0 -243
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
// /feedback Claude Code slash command.
|
|
4
4
|
//
|
|
5
5
|
// Resolves the LATEST feedback bundle the Bongos app wrote to
|
|
6
|
-
// ~/CloudBongos/feedback/ (via the shared `latest` pointer
|
|
7
|
-
//
|
|
6
|
+
// ~/CloudBongos/feedback/ (via the shared `latest` pointer, ADR 0087) and
|
|
7
|
+
// prints it for a Claude Code session:
|
|
8
8
|
//
|
|
9
9
|
// 1. the full prompt.md body (the model-agnostic transcript + ask, R11), and
|
|
10
10
|
// 2. the ABSOLUTE path of every attached frame, on its own line, so Claude's
|
|
@@ -20,13 +20,139 @@
|
|
|
20
20
|
//
|
|
21
21
|
// Local + read-only: it reads files under your home dir. No GDS session, no
|
|
22
22
|
// network — so it works on any machine the Bongos app runs on.
|
|
23
|
+
//
|
|
24
|
+
// resolveLatest + feedbackBaseDir are ported here from the app's
|
|
25
|
+
// bongos-app/src/handoff.js, which no longer lives in this repo (the desktop
|
|
26
|
+
// apps publish off-repo, ADR 0098 — task 1004356). The contract is ADR 0087's:
|
|
27
|
+
// `latest.json` is authoritative, the `latest/` symlink is a convenience that
|
|
28
|
+
// may be absent, and with neither the reader self-heals by scanning for the
|
|
29
|
+
// newest bundle dir holding a prompt.md.
|
|
23
30
|
|
|
24
31
|
'use strict';
|
|
25
32
|
|
|
33
|
+
const fs = require('node:fs/promises');
|
|
34
|
+
const os = require('node:os');
|
|
26
35
|
const path = require('node:path');
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
|
|
37
|
+
const IMAGE_EXT = new Set(['.png', '.jpg', '.jpeg', '.webp', '.gif']);
|
|
38
|
+
|
|
39
|
+
/** Where the Bongos app writes bundles: ~/CloudBongos/feedback. */
|
|
40
|
+
function feedbackBaseDir() {
|
|
41
|
+
return path.join(os.homedir(), 'CloudBongos', 'feedback');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function isBundleDir(dir) {
|
|
45
|
+
try {
|
|
46
|
+
return (await fs.stat(path.join(dir, 'prompt.md'))).isFile();
|
|
47
|
+
} catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// The dir `latest.json` names, or null if it is missing, unreadable or stale.
|
|
53
|
+
// Accepts the pointer by `dir` (absolute) or by `id` (a child of baseDir).
|
|
54
|
+
async function fromPointer(baseDir) {
|
|
55
|
+
let ptr;
|
|
56
|
+
try {
|
|
57
|
+
ptr = JSON.parse(await fs.readFile(path.join(baseDir, 'latest.json'), 'utf8'));
|
|
58
|
+
} catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
if (!ptr || typeof ptr !== 'object') return null;
|
|
62
|
+
const candidates = [];
|
|
63
|
+
if (typeof ptr.dir === 'string' && ptr.dir) candidates.push(path.resolve(baseDir, ptr.dir));
|
|
64
|
+
if (typeof ptr.id === 'string' && ptr.id && !/[\\/]/.test(ptr.id)) candidates.push(path.join(baseDir, ptr.id));
|
|
65
|
+
for (const dir of candidates) if (await isBundleDir(dir)) return dir;
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function fromSymlink(baseDir) {
|
|
70
|
+
const link = path.join(baseDir, 'latest');
|
|
71
|
+
if (!(await isBundleDir(link))) return null;
|
|
72
|
+
try {
|
|
73
|
+
return await fs.realpath(link);
|
|
74
|
+
} catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Self-heal: the newest child dir (by prompt.md mtime, then name) with a prompt.md.
|
|
80
|
+
async function fromScan(baseDir) {
|
|
81
|
+
let entries;
|
|
82
|
+
try {
|
|
83
|
+
entries = await fs.readdir(baseDir, { withFileTypes: true });
|
|
84
|
+
} catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
let best = null;
|
|
88
|
+
for (const e of entries) {
|
|
89
|
+
if (!e.isDirectory() || e.name === 'latest') continue;
|
|
90
|
+
const dir = path.join(baseDir, e.name);
|
|
91
|
+
let st;
|
|
92
|
+
try {
|
|
93
|
+
st = await fs.stat(path.join(dir, 'prompt.md'));
|
|
94
|
+
} catch {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (!st.isFile()) continue;
|
|
98
|
+
if (!best || st.mtimeMs > best.mtimeMs || (st.mtimeMs === best.mtimeMs && e.name > best.name)) {
|
|
99
|
+
best = { dir, name: e.name, mtimeMs: st.mtimeMs };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return best && best.dir;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// The bundle's frames as absolute paths: those prompt.md references (in the
|
|
106
|
+
// order the walkthrough cites them) that exist, then any other image in the dir.
|
|
107
|
+
async function collectImages(dir, promptMarkdown) {
|
|
108
|
+
const out = [];
|
|
109
|
+
const seen = new Set();
|
|
110
|
+
const add = (p) => {
|
|
111
|
+
const key = process.platform === 'win32' ? p.toLowerCase() : p;
|
|
112
|
+
if (!seen.has(key)) { seen.add(key); out.push(p); }
|
|
113
|
+
};
|
|
114
|
+
for (const m of promptMarkdown.matchAll(/!\[[^\]]*\]\(\s*<?([^)>]+?)>?\s*\)/g)) {
|
|
115
|
+
const p = path.resolve(dir, m[1]);
|
|
116
|
+
if (!IMAGE_EXT.has(path.extname(p).toLowerCase())) continue;
|
|
117
|
+
try {
|
|
118
|
+
if ((await fs.stat(p)).isFile()) add(p);
|
|
119
|
+
} catch { /* referenced but absent — skip */ }
|
|
120
|
+
}
|
|
121
|
+
const walk = async (d, depth) => {
|
|
122
|
+
let entries;
|
|
123
|
+
try {
|
|
124
|
+
entries = await fs.readdir(d, { withFileTypes: true });
|
|
125
|
+
} catch {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
129
|
+
for (const e of entries) {
|
|
130
|
+
const p = path.join(d, e.name);
|
|
131
|
+
if (e.isDirectory() && depth > 0) await walk(p, depth - 1);
|
|
132
|
+
else if (e.isFile() && IMAGE_EXT.has(path.extname(e.name).toLowerCase())) add(p);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
await walk(dir, 1);
|
|
136
|
+
return out;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The newest feedback bundle under baseDir, or null if there is none.
|
|
141
|
+
* @returns {Promise<null|{id:string,dir:string,promptPath:string,promptMarkdown:string,imagePaths:string[]}>}
|
|
142
|
+
*/
|
|
143
|
+
async function resolveLatest(baseDir = feedbackBaseDir()) {
|
|
144
|
+
const dir = (await fromPointer(baseDir)) || (await fromSymlink(baseDir)) || (await fromScan(baseDir));
|
|
145
|
+
if (!dir) return null;
|
|
146
|
+
const promptPath = path.join(dir, 'prompt.md');
|
|
147
|
+
const promptMarkdown = await fs.readFile(promptPath, 'utf8');
|
|
148
|
+
return {
|
|
149
|
+
id: path.basename(dir),
|
|
150
|
+
dir,
|
|
151
|
+
promptPath,
|
|
152
|
+
promptMarkdown,
|
|
153
|
+
imagePaths: await collectImages(dir, promptMarkdown),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
30
156
|
|
|
31
157
|
function parseArgs(argv) {
|
|
32
158
|
const out = { json: false, base: undefined };
|
|
@@ -88,7 +214,11 @@ async function main() {
|
|
|
88
214
|
process.stdout.write(`${lines.join('\n')}\n`);
|
|
89
215
|
}
|
|
90
216
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
217
|
+
module.exports = { resolveLatest, feedbackBaseDir };
|
|
218
|
+
|
|
219
|
+
if (require.main === module) {
|
|
220
|
+
main().catch((err) => {
|
|
221
|
+
process.stderr.write(`feedback-latest: ${err.message}\n`);
|
|
222
|
+
process.exitCode = 1;
|
|
223
|
+
});
|
|
224
|
+
}
|
|
@@ -71,10 +71,6 @@ const IDENTITY_SCAN_EXTRA_FILES = [];
|
|
|
71
71
|
// one, and any file NOT listed must have zero hits. Getting better never fails.
|
|
72
72
|
//
|
|
73
73
|
// Why each is legitimate:
|
|
74
|
-
// * box.js — REAL Cloudflare/DNS zone names for the operator plane
|
|
75
|
-
// (`dev.<host>`, the terminal zone). These are infrastructure identifiers,
|
|
76
|
-
// not an instance URL; routing them through branding would be wrong. (Its
|
|
77
|
-
// two genuine API-base defaults WERE fixed in 1002428.)
|
|
78
74
|
// * publish-manifest.js — the literal FILENAMES of three real committed docs
|
|
79
75
|
// (the two decouple recipes, plus the instance's own name/trademark ADR that
|
|
80
76
|
// task 1003869 excluded: its prose redacts cleanly but the FILENAME rides in
|
|
@@ -91,8 +87,8 @@ const IDENTITY_SCAN_EXTRA_FILES = [];
|
|
|
91
87
|
// 1002567). Each is a HOST-PINNED OPS script, not portable code: they name the
|
|
92
88
|
// live box's actual Postgres database/role and its actual /etc secrets dir, and
|
|
93
89
|
// every one of those literals is already only the DEFAULT behind an env override
|
|
94
|
-
// (GDS_BACKUP_DB, PROD_DB/STAGING_DB, PG_SOCKET).
|
|
95
|
-
//
|
|
90
|
+
// (GDS_BACKUP_DB, PROD_DB/STAGING_DB, PG_SOCKET). Each is an infrastructure
|
|
91
|
+
// identifier, not an instance URL, and the systemd
|
|
96
92
|
// units on that box invoke these by path. Re-pointing an instance's backups is
|
|
97
93
|
// deployment work, not a branding read. Their COUNT is still frozen here, so a
|
|
98
94
|
// NEW literal in any of them fails exactly like one in an unlisted file.
|
|
@@ -116,7 +112,6 @@ const IDENTITY_SCAN_ALLOWED = {
|
|
|
116
112
|
// instance it declines to run instead of destroying the wrong database.
|
|
117
113
|
'scripts/gds/seed-staging.sh': 4,
|
|
118
114
|
'scripts/gds/backfill-sessions.js': 2,
|
|
119
|
-
'scripts/gds/box.js': 3,
|
|
120
115
|
'scripts/gds/publish-manifest.js': 3,
|
|
121
116
|
'scripts/gds/seed-bongos-coreB-tranche1-tasks.js': 1,
|
|
122
117
|
'scripts/gds/seed-bongos-coreB-tranche2-tasks.js': 1,
|
|
@@ -46,6 +46,10 @@ const WRITE_VALIDATION_EXEMPT = new Set([
|
|
|
46
46
|
// the route's own express.raw parser and read by docx.readUpload, which refuses
|
|
47
47
|
// anything that is not a bounded, readable Word file (not_a_docx / upload_too_large).
|
|
48
48
|
'POST /copy-desk/pages/:pageId/draft.docx',
|
|
49
|
+
// Not a JSON body either: the raw module tarball (task 1004271, ADR 0338 D1), capped by
|
|
50
|
+
// the route's express.raw parser and read by module-artifact.verifyModuleArtifact, which
|
|
51
|
+
// recomputes every hash and refuses anything that is not a well-formed module version.
|
|
52
|
+
'POST /store/modules/:key/versions',
|
|
49
53
|
]);
|
|
50
54
|
|
|
51
55
|
// KNOWN GAPS, NOT EXEMPTIONS (task 1002551 / BV1.R109b → tracked by task 1002552).
|
|
@@ -284,9 +284,9 @@ function knipIssueCount() {
|
|
|
284
284
|
// baseline map leaves every `floor === undefined`, and compareToBaselines classifies
|
|
285
285
|
// an absent floor as a WARNING — so a checkout with no config/ reported the ratchet
|
|
286
286
|
// as PASSED. Measured: with the baselines gone, a planted 5,000-line and 94-cycle
|
|
287
|
-
// regression produced 0 violations. That
|
|
288
|
-
//
|
|
289
|
-
//
|
|
287
|
+
// regression produced 0 violations. That was not a hypothetical checkout — a sparse
|
|
288
|
+
// checkout without `config/` once left the builders who most needed the gate
|
|
289
|
+
// silently exempt from it, learning from red CI instead.
|
|
290
290
|
//
|
|
291
291
|
// Distinguish the two absences, because they are not the same fact:
|
|
292
292
|
// - the FILE is missing/malformed -> cannot verify anything -> hard fail (here);
|
|
@@ -315,7 +315,7 @@ function readBaselines(baselinePath = BASELINE_PATH) {
|
|
|
315
315
|
metrics: {},
|
|
316
316
|
error: missing
|
|
317
317
|
? `config/fitness-baselines.json is MISSING — the quality ratchet cannot verify anything, so it fails CLOSED rather than reporting a pass it did not check. `
|
|
318
|
-
+ `If this is a
|
|
318
|
+
+ `If this is a sparse or partial checkout, take the whole tree (\`git sparse-checkout disable\`). `
|
|
319
319
|
+ `To bootstrap a fresh baseline deliberately: node scripts/gds/fitness-ratchets.js --update-baselines`
|
|
320
320
|
: `config/fitness-baselines.json is unreadable (${e && e.message}) — failing CLOSED.`,
|
|
321
321
|
};
|
package/scripts/gds/fitness.js
CHANGED
|
@@ -343,11 +343,11 @@ function checkDeterministicRoutines() {
|
|
|
343
343
|
// published doorway); the core NEVER imports a module; a module NEVER imports a
|
|
344
344
|
// sibling module. These two checks enforce it.
|
|
345
345
|
//
|
|
346
|
-
// Both were GREEN through the strangler:
|
|
347
|
-
//
|
|
346
|
+
// Both were GREEN through the strangler: the first two moved modules (M07/M08)
|
|
347
|
+
// imported only the doorway, and the core imported neither. The boundary
|
|
348
348
|
// shipped in WARN mode so a half-moved module mid-migration couldn't red the
|
|
349
349
|
// build; BV1.R45 (task 1414) flips it to ENFORCING now that the first move
|
|
350
|
-
// (
|
|
350
|
+
// (M07) proved clean — the monotonic ratchet (ADR 0062 §9 / design
|
|
351
351
|
// 04§3). A NEW cross-boundary import is now a red build; warn-mode is gone.
|
|
352
352
|
let MODULE_BOUNDARY_ENFORCING = true;
|
|
353
353
|
const MODULE_API_REL = 'src/module-api.js';
|
|
@@ -497,7 +497,7 @@ function checkScopeMapImportsProtected() {
|
|
|
497
497
|
// module-AGNOSTIC: it discovers, validates, and mounts modules uniformly and may
|
|
498
498
|
// never special-case one by name. The import checks (Check 7/8) stop a module's
|
|
499
499
|
// CODE from being reached by `require`; this stops a module's IDENTITY from being
|
|
500
|
-
// hardcoded into the kernel (`if (key === '
|
|
500
|
+
// hardcoded into the kernel (`if (key === 'art-pipeline') …`, a copied module helper,
|
|
501
501
|
// a registry entry that should have moved out). "No module-specific code" is
|
|
502
502
|
// operationalized as the one drift-free signal — the kernel names no discovered
|
|
503
503
|
// module KEY (the canonical id from modules/<key>/module.json). Domain terms are
|
|
@@ -606,14 +606,14 @@ const KERNEL_FILES = [
|
|
|
606
606
|
// Kernel files exempt from the no-module-keys scan (Check 10) because naming a
|
|
607
607
|
// module is, for them, the JOB — they stay in KERNEL_FILES for the import check
|
|
608
608
|
// (Check 12), which guards dependency *direction* (a much stronger guarantee than
|
|
609
|
-
// "never write the string '
|
|
609
|
+
// "never write the string 'art-pipeline'"). Two legitimate reasons a kernel file names
|
|
610
610
|
// a module:
|
|
611
611
|
// • the REGISTRY — module-scope-map.js IS the module→path map (and
|
|
612
612
|
// checkScopeMapImportsProtected already guards how it derives `protected`).
|
|
613
613
|
// • the TRUST BOUNDARY — auth.js carries the Discord OAuth account-LINK flow
|
|
614
614
|
// (core by design — see modules/discord/CLAUDE.md "NOT in this module"); and
|
|
615
615
|
// permission-path-check.js / route-rank-check.js MUST name module path
|
|
616
|
-
// subtrees ('modules/
|
|
616
|
+
// subtrees ('modules/grading/', …) to protect + rank-gate them. Forbidding
|
|
617
617
|
// these the string would force the trust layer to stop protecting module
|
|
618
618
|
// surfaces — exactly backwards. The generic machinery + data + config files
|
|
619
619
|
// (module-api, the loader, db-kernel, secret-box, pool, _helpers, branding,
|
|
@@ -683,8 +683,8 @@ function moduleDir(key) {
|
|
|
683
683
|
return path.join(CORE_ROOT, 'modules', key);
|
|
684
684
|
}
|
|
685
685
|
|
|
686
|
-
// Match a module key as a DELIMITED token so `
|
|
687
|
-
// `mount('
|
|
686
|
+
// Match a module key as a DELIMITED token so `art-pipeline` hits in `'art-pipeline'` /
|
|
687
|
+
// `mount('art-pipeline')` but never inside `art-pipelines` or `xart-pipeline`. Hyphens are
|
|
688
688
|
// non-word chars, so the boundary guards against word-chars AND hyphens on both
|
|
689
689
|
// sides (no lookbehind — portable on every node the unit gate runs).
|
|
690
690
|
function keyTokenRe(key) {
|
|
@@ -816,7 +816,7 @@ function checkKernelImportsNoDomain() {
|
|
|
816
816
|
// migrations," never "drop its tables" (ADR 0083 §Module-owned migrations);
|
|
817
817
|
// there is no down path, so a DROP/TRUNCATE can only be an accident.
|
|
818
818
|
// • NAMESPACED — every object it CREATEs lives under the <key>_ prefix
|
|
819
|
-
// (
|
|
819
|
+
// (art-pipeline → art_pipeline_), and it may only ALTER its own namespaced tables;
|
|
820
820
|
// core/sibling state is reached through the doorway/seams, never raw DDL.
|
|
821
821
|
//
|
|
822
822
|
// LEGACY_NAMESPACED: tables that predate the <key>_-prefix convention (created before the module
|
|
@@ -848,7 +848,7 @@ const CREATE_OBJ_RE = /\bcreate\s+(?:or\s+replace\s+)?(?:unique\s+)?(?:materiali
|
|
|
848
848
|
const CREATE_INDEX_RE = /\bcreate\s+(?:unique\s+)?index\s+(?:concurrently\s+)?(?:if\s+not\s+exists\s+)?(?:"?[\w.]+"?)\s+on\s+(?:only\s+)?("?[\w.]+"?)/gi;
|
|
849
849
|
const ALTER_TABLE_RE = /\balter\s+table\s+(?:if\s+exists\s+)?(?:only\s+)?("?[\w.]+"?)/gi;
|
|
850
850
|
|
|
851
|
-
// SQL object-namespace prefix for a module key:
|
|
851
|
+
// SQL object-namespace prefix for a module key: art-pipeline → art_pipeline (SQL-safe).
|
|
852
852
|
function moduleNamespace(key) { return key.replace(/-/g, '_'); }
|
|
853
853
|
|
|
854
854
|
// strip SQL comments so a commented-out statement is never scanned
|
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
// 05-versioning ← live versions (id/status)
|
|
9
9
|
// 03-drachmae-karma ← per-piece backing-task status + seeded-achievement count
|
|
10
10
|
// 04-architecture ← per-piece backing-task status: the ADR 0024 memory
|
|
11
|
-
// chain + the
|
|
12
|
-
//
|
|
13
|
-
//
|
|
11
|
+
// chain + the machine → prod ship flow, in one
|
|
12
|
+
// "complete architecture" map (consolidated under
|
|
13
|
+
// task 1059)
|
|
14
14
|
//
|
|
15
15
|
// It writes each .mmd from a template, renders the SVG (crisp, pannable) + PNG
|
|
16
16
|
// (fallback) via scripts/render-diagrams.sh, and rewrites the data-driven slices
|
|
@@ -332,17 +332,18 @@ function drachmaeKarmaMmd(f) {
|
|
|
332
332
|
}
|
|
333
333
|
|
|
334
334
|
// 04-architecture. The complete picture: where a builder's work runs and how it
|
|
335
|
-
// reaches production, with the per-builder memory layer (ADR 0024) folded in
|
|
336
|
-
//
|
|
337
|
-
//
|
|
338
|
-
//
|
|
339
|
-
// backing Bongos task is 'shipped', dotted/PLANNED otherwise — so the map is an
|
|
340
|
-
// honest snapshot that flips itself as pieces ship (or regresses if one is
|
|
335
|
+
// reaches production, with the per-builder memory layer (ADR 0024) folded in
|
|
336
|
+
// (task 1059). Conceptual like 03: every feature-piece + flow edge is LIVE/solid
|
|
337
|
+
// iff its backing Bongos task is 'shipped', dotted/PLANNED otherwise — so the map
|
|
338
|
+
// is an honest snapshot that flips itself as pieces ship (or regresses if one is
|
|
341
339
|
// reopened). Pieces → live task ids:
|
|
342
340
|
// memory layer : 273 schema · 274 sync-on-ship · 275 pull-on-start · 276 isolation
|
|
343
|
-
//
|
|
344
|
-
//
|
|
345
|
-
//
|
|
341
|
+
// ship flow : 1025 publish-via-server · 1028 GitHub App push credential
|
|
342
|
+
// Work runs on the builder's own machine, in a clone of the instance repo. It
|
|
343
|
+
// reaches main one of two ways (ship-deploy-target.js `pushVia`): a machine
|
|
344
|
+
// signed in to GitHub pushes its branch and opens the PR itself; a checkout with
|
|
345
|
+
// no push credential uploads the branch as a git bundle and the SERVER pushes it
|
|
346
|
+
// with its own credential (ADR 0055).
|
|
346
347
|
function architectureMmd(f) {
|
|
347
348
|
const c = f.conceptual;
|
|
348
349
|
const { host } = brand();
|
|
@@ -370,16 +371,16 @@ function architectureMmd(f) {
|
|
|
370
371
|
? 'SRVMEM -->|"pull on session start"| LOCAL'
|
|
371
372
|
: 'SRVMEM -.->|"pull on session start — PLANNED"| LOCAL';
|
|
372
373
|
|
|
373
|
-
// ---
|
|
374
|
+
// --- ship flow: the server's push credential + closing note ---
|
|
374
375
|
const pushCred = shipped(1028)
|
|
375
376
|
? 'GitHub App, short-lived tokens'
|
|
376
377
|
: 'standing push PAT (GitHub App pending — 1028)';
|
|
377
|
-
//
|
|
378
|
-
//
|
|
379
|
-
//
|
|
380
|
-
const chainLive = [
|
|
378
|
+
// Both ways onto main LIVE? NB the deploy leg is the standalone AUTO-PULL
|
|
379
|
+
// (ADR 0108/0129), not a task-gated GitHub-Actions CI job — so 859 (CI deploy)
|
|
380
|
+
// is intentionally NOT in this set.
|
|
381
|
+
const chainLive = [1025, 1028].every(shipped);
|
|
381
382
|
const closingNote = chainLive
|
|
382
|
-
? '
|
|
383
|
+
? 'Both ways onto main work today: a machine signed in to GitHub pushes its own branch, and a checkout without a push credential uploads it for the server to push. Either way the instance auto-pulls and redeploys.'
|
|
383
384
|
: `Still landing (PLANNED): the server-mediated publish (${tag(1025)} · 1025) and the GitHub App push credential (${tag(1028)} · 1028).`;
|
|
384
385
|
|
|
385
386
|
// Product-neutral runtime label: the instance's own product name (branding),
|
|
@@ -389,30 +390,22 @@ function architectureMmd(f) {
|
|
|
389
390
|
const appLabel = productName && productName !== 'Cloud Bongos' ? productName : 'app';
|
|
390
391
|
|
|
391
392
|
// Layout: ELK engine, top-down (task 1066). ELK minimizes edge crossings far
|
|
392
|
-
// better than the default renderer
|
|
393
|
-
//
|
|
394
|
-
//
|
|
395
|
-
//
|
|
396
|
-
//
|
|
397
|
-
// memory
|
|
398
|
-
//
|
|
399
|
-
//
|
|
400
|
-
//
|
|
401
|
-
//
|
|
402
|
-
//
|
|
403
|
-
//
|
|
404
|
-
//
|
|
405
|
-
//
|
|
406
|
-
//
|
|
407
|
-
//
|
|
408
|
-
// instead of detouring the full height past a mid-stack GitHub. The deploy is
|
|
409
|
-
// the STANDALONE auto-pull (ADR 0108/0129): merge to the instance's own main →
|
|
410
|
-
// the server pulls its own repo → migrate/regenerate/restart → the live app —
|
|
411
|
-
// NOT a GitHub-Actions push-deploy (that was the reference monorepo's model).
|
|
412
|
-
// NOTE on direction: we keep TB,
|
|
413
|
-
// not a repo-on-the-left LR/RL — the flow is an ~8-deep linear chain, so a
|
|
414
|
-
// sideways layout stretches into an unreadable ~5:1 strip; top-down keeps a
|
|
415
|
-
// legible aspect.
|
|
393
|
+
// better than the default renderer. Two declutter moves: (1) the INTRA-cluster
|
|
394
|
+
// wiring (worker→its files, api→db/rank, db→memory-store) is dropped —
|
|
395
|
+
// co-location inside a labelled subgraph already says "these belong together";
|
|
396
|
+
// only the CROSS-cluster flow (the numbered ship steps, memory sync,
|
|
397
|
+
// claim/ship) is drawn. (2) Low-signal annotation edges (DB-is-king,
|
|
398
|
+
// memory-follows-you) are folded into node labels. WATERFALL ordering (task
|
|
399
|
+
// 1073, off Lars's "put the GitHub box last"): subgraphs are declared in flow
|
|
400
|
+
// order MACHINE→SERVER→GH, and the live app (the instance's product runtime)
|
|
401
|
+
// is pulled OUT of the SERVER cluster into its own terminal node at the very
|
|
402
|
+
// bottom (annotated "same server · same Node process" so it stays honest), so
|
|
403
|
+
// the deploy is the LAST forward step instead of an edge looping back UP into
|
|
404
|
+
// the server. The deploy is the STANDALONE auto-pull (ADR 0108/0129): merge to
|
|
405
|
+
// the instance's own main → the server pulls its own repo →
|
|
406
|
+
// migrate/regenerate/restart → the live app — NOT a GitHub-Actions push-deploy
|
|
407
|
+
// (that was the reference monorepo's model). NOTE on direction: we keep TB,
|
|
408
|
+
// not LR — a sideways layout stretches the chain into an unreadable strip.
|
|
416
409
|
const lines = [
|
|
417
410
|
'---',
|
|
418
411
|
'title: The complete architecture — where your work runs and how it reaches production (AUTO-GENERATED from live facts — do not hand-edit; see scripts/gds/gen-diagrams.js)',
|
|
@@ -420,18 +413,10 @@ function architectureMmd(f) {
|
|
|
420
413
|
' layout: elk',
|
|
421
414
|
'---',
|
|
422
415
|
'flowchart TB',
|
|
423
|
-
' subgraph
|
|
424
|
-
'
|
|
425
|
-
'
|
|
426
|
-
'',
|
|
427
|
-
' subgraph BOX["DEV BOX — a machine WE create on DigitalOcean (gated · revocable · audited; Metic+ may instead clone locally)"]',
|
|
428
|
-
' WORKER["Claude Code WORKER\\n(opens files · runs commands · runs the /builder-* skills)"]',
|
|
429
|
-
` CODE["the code — git clone + per-builder worktrees (.claude/worktrees/*)\\nfor sub-Metic builders it lives ONLY here · CLAUDE.md is DESCRIPTIVE only"]`,
|
|
416
|
+
' subgraph MACHINE["YOUR MACHINE — a clone of the instance repo"]',
|
|
417
|
+
' WORKER["Claude Code — the desktop app or the terminal\\n(opens files · runs commands · runs the /builder-* skills)"]',
|
|
418
|
+
' CODE["the code — git clone + per-task worktrees (.claude/worktrees/*)\\nCLAUDE.md is DESCRIPTIVE only"]',
|
|
430
419
|
' LOCAL["local ~/.claude memory\\nMAP = MEMORY.md — a one-line index loaded EVERY session\\n(a guard + auto-tidy keep it light; ADR 0074)\\n+ drawer of full notes, loaded only on demand"]',
|
|
431
|
-
' ORIGIN["credential-less git origin\\n(NO GitHub push secret on the box — by design)"]',
|
|
432
|
-
` BOXTOK["box-scoped Bongos token\\n(deny-by-default: bootstrap endpoints only;\\nrejected for branch upload → re-auth first — ${tag(919)})"]`,
|
|
433
|
-
` PREVIEW["sandbox preview server on :3000\\n→ a per-builder sandbox URL (${tag(897)})"]`,
|
|
434
|
-
` SWITCH["on / off + browser terminal\\n(desktop app ${tag(904)} · ttyd-over-tunnel ${tag(774)})"]`,
|
|
435
420
|
' end',
|
|
436
421
|
'',
|
|
437
422
|
` subgraph SERVER["THE INSTANCE SERVER — ${host} (the authority AND production)"]`,
|
|
@@ -440,7 +425,7 @@ function architectureMmd(f) {
|
|
|
440
425
|
' DB["Postgres — tasks · claims · versions · builders.rank\\ncredit_log · grades · idea_inbox · builder_memory\\n(KING for work-state + permissions; CLAUDE.md only describes it)"]',
|
|
441
426
|
' RANK["auth.requireRank — checked per request, NO caching\\n(ADR 0016: a demotion takes effect on the next request)"]',
|
|
442
427
|
` SRVMEM["server-side builder_memory store\\n${memLead}: per-builder · isolated · forensic read at Metic+ (ADR 0157)\\nyour memory follows you across machines & worktrees\\n/recall fetches only the relevant subset (ADR 0060)\\n(${memStatus})"]`,
|
|
443
|
-
` PUSHTOK["server-held push credential\\n(${pushCred} —
|
|
428
|
+
` PUSHTOK["server-held push credential\\n(${pushCred} — for a checkout that has none of its own)"]`,
|
|
444
429
|
' DEPLOY["auto-pull deploy (ADR 0129)\\na timer pulls THIS instance repo every ~2 min →\\nnpm ci if the pin changed → migrate → regenerate docs → restart → healthz"]',
|
|
445
430
|
' end',
|
|
446
431
|
'',
|
|
@@ -450,17 +435,14 @@ function architectureMmd(f) {
|
|
|
450
435
|
'',
|
|
451
436
|
` LIVEAPP["the live ${appLabel} — ${host}\\n(same server · same Node process as /api/bongos/*)"]`,
|
|
452
437
|
'',
|
|
453
|
-
'
|
|
454
|
-
'
|
|
455
|
-
'
|
|
456
|
-
'
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
' MAIN -->|"6 · the instance auto-pulls its own main"| DEPLOY',
|
|
460
|
-
' DEPLOY -->|"7 · migrate · regenerate docs · restart"| LIVEAPP',
|
|
438
|
+
' WORKER -->|"1 · edit + commit"| CODE',
|
|
439
|
+
' WORKER -->|"2 · push the branch + open a PR (a machine signed in to GitHub)"| MAIN',
|
|
440
|
+
flow('WORKER', 1025, '2 · or upload the branch as a git bundle (no push credential here)', 'API'),
|
|
441
|
+
flow('API', 1025, `3 · the server pushes it + opens the PR (${tag(1025)})`, 'MAIN'),
|
|
442
|
+
' MAIN -->|"4 · the instance auto-pulls its own main"| DEPLOY',
|
|
443
|
+
' DEPLOY -->|"5 · migrate · regenerate docs · restart"| LIVEAPP',
|
|
461
444
|
' CORE --- API',
|
|
462
445
|
' PUSHTOK -.-> API',
|
|
463
|
-
' ORIGIN -. "direct push blocked" .-> MAIN',
|
|
464
446
|
' API -. "claim / ship / cost" .-> WORKER',
|
|
465
447
|
` ${pushEdge}`,
|
|
466
448
|
` ${pullEdge}`,
|
|
@@ -500,20 +482,16 @@ function rebuildAssertions(prev, f) {
|
|
|
500
482
|
pending_tasks: ids.filter((id) => !shipped(id)).map(entry),
|
|
501
483
|
});
|
|
502
484
|
|
|
503
|
-
// 04-architecture — the ADR 0024 memory chain + the
|
|
504
|
-
// flow
|
|
505
|
-
const arch = split([273, 274, 275, 276,
|
|
485
|
+
// 04-architecture — the ADR 0024 memory chain + the machine → prod ship
|
|
486
|
+
// flow (task 1059). A piece is LIVE iff its backing task is shipped.
|
|
487
|
+
const arch = split([273, 274, 275, 276, 1025, 1028]);
|
|
506
488
|
next.architecture = {
|
|
507
489
|
diagram: '04-architecture',
|
|
508
490
|
_comment:
|
|
509
|
-
"Pieces of 04-architecture gated on a backing Bongos task. A piece is LIVE iff its task is 'shipped'; live_tasks must ALL be shipped, pending_tasks must NOT yet be. Rebuilt by scripts/gds/gen-diagrams.js in lockstep with the diagram, so this is the drift checker's backstop. The
|
|
491
|
+
"Pieces of 04-architecture gated on a backing Bongos task. A piece is LIVE iff its task is 'shipped'; live_tasks must ALL be shipped, pending_tasks must NOT yet be. Rebuilt by scripts/gds/gen-diagrams.js in lockstep with the diagram, so this is the drift checker's backstop. The machine/server/GitHub topology is structural (not task-gated); these are the LIVE/PLANNED markers. MEMORY layer (ADR 0024): 273 schema / 274 sync-on-ship / 275 pull-on-start / 276 isolation. Ship flow: 1025 (server-mediated publish, for a checkout with no push credential), 1028 (GitHub App push credential). The deploy leg is the standalone AUTO-PULL (ADR 0108/0129), not a task-gated GitHub-Actions CI job, so 859 is intentionally absent.",
|
|
510
492
|
live_tasks: arch.live_tasks,
|
|
511
493
|
pending_tasks: arch.pending_tasks,
|
|
512
494
|
};
|
|
513
|
-
// Drop the two slices this diagram replaced so the file (and drift checker)
|
|
514
|
-
// never carry stale keys after the 04+06 consolidation.
|
|
515
|
-
delete next.server_repo_memory;
|
|
516
|
-
delete next.dev_box;
|
|
517
495
|
|
|
518
496
|
// 03-drachmae-karma — bounty + karma pieces (D_SHIP/D_ACH have no task gate).
|
|
519
497
|
const dk = split([284, 286, 282, 245, 248, 246]);
|
|
@@ -1,24 +1,18 @@
|
|
|
1
|
-
// scripts/gds/http-api-client.js — the
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// (do-api.js's design note: the box subsystem keeps "ONE shape for every external
|
|
6
|
-
// API"). This base IS that one shape.
|
|
1
|
+
// scripts/gds/http-api-client.js — the request skeleton behind the control
|
|
2
|
+
// plane's JSON-over-HTTP client, scripts/gds/do-api.js (DoApi, DigitalOcean): a
|
|
3
|
+
// thin, injectable-transport, dry-run-by-default wrapper. It is kept apart from
|
|
4
|
+
// do-api.js so the ONE request shape stays reusable by any future client.
|
|
7
5
|
//
|
|
8
|
-
//
|
|
9
|
-
// - the constructor's OWN live-mode validation (
|
|
10
|
-
//
|
|
11
|
-
// - requestInit() — extra fetch options (Cloudflare pins an IPv4 dispatcher,
|
|
12
|
-
// #771; DigitalOcean sends none);
|
|
6
|
+
// Per-API differences go in a subclass via three small hooks:
|
|
7
|
+
// - the constructor's OWN live-mode validation (its "missing X" messages);
|
|
8
|
+
// - requestInit() — extra fetch options (DigitalOcean sends none);
|
|
13
9
|
// - detectError() — what counts as a failure + how the message is extracted
|
|
14
|
-
// (DigitalOcean = non-2xx → message/id
|
|
15
|
-
// envelope and joins errors[]).
|
|
10
|
+
// (DigitalOcean = non-2xx → message/id).
|
|
16
11
|
//
|
|
17
|
-
//
|
|
18
|
-
// tests/cf_tunnel.mjs (CfTunnelApi).
|
|
12
|
+
// Pinned by tests/do_api.mjs.
|
|
19
13
|
|
|
20
14
|
// Build a distinct, named API-error class. Each client makes its own so the
|
|
21
|
-
// `instanceof` checks the tests rely on (DoApiError
|
|
15
|
+
// `instanceof` checks the tests rely on (DoApiError) stay meaningful
|
|
22
16
|
// and the `.name` / `.code` carried on every thrown error survive unchanged.
|
|
23
17
|
function makeApiError(name, code) {
|
|
24
18
|
return class ApiError extends Error {
|
|
@@ -46,13 +40,12 @@ class JsonHttpApi {
|
|
|
46
40
|
this._ErrorClass = ErrorClass;
|
|
47
41
|
}
|
|
48
42
|
|
|
49
|
-
// Extra fetch init merged into every LIVE request. Base sends none
|
|
50
|
-
// overrides to pin the IPv4 dispatcher (its token is IP-locked, #771).
|
|
43
|
+
// Extra fetch init merged into every LIVE request. Base sends none.
|
|
51
44
|
requestInit() { return {}; }
|
|
52
45
|
|
|
53
46
|
// Inspect a completed response. Return an error MESSAGE string to throw, or null
|
|
54
47
|
// to accept. Base fails on a non-2xx HTTP status (DigitalOcean surfaces
|
|
55
|
-
// message/id)
|
|
48
|
+
// message/id).
|
|
56
49
|
detectError(res, json) {
|
|
57
50
|
if (!res.ok) return (json && (json.message || json.id)) || `HTTP ${res.status}`;
|
|
58
51
|
return null;
|
package/scripts/gds/init.js
CHANGED
|
@@ -79,7 +79,7 @@ const { detectStack, formatStackSummary } = require('./adopt-detect'); // ADR 01
|
|
|
79
79
|
const { resolveBacklogTasks, DEFAULT_MAX: BACKLOG_MAX } = require('./adopt-import'); // ADR 0121 §Decision 3 (task 2044): import an existing backlog
|
|
80
80
|
const { preflightAdopt, formatPreflight } = require('./adopt-preflight'); // ADR 0121 §Decision 5 (task 2045): the accept-gated conflict pre-flight
|
|
81
81
|
|
|
82
|
-
const KNOWN_MODULES = ['game', 'art-pipeline', 'discord'
|
|
82
|
+
const KNOWN_MODULES = ['game', 'art-pipeline', 'discord'];
|
|
83
83
|
|
|
84
84
|
// The provisioning hosting shapes — a small mirror of modules/provisioning's
|
|
85
85
|
// HOSTING_SHAPES. init deliberately does NOT import the (optional) provisioning
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// lint-infra-exec.js — task 2137 (ADR 0108 configurable-root). The dry-run/lint that proves every
|
|
4
4
|
// host systemd unit running a CORE script still resolves AFTER the R89 split.
|
|
5
5
|
//
|
|
6
|
-
// The units (
|
|
6
|
+
// The units (cohost-*, provision-*, search-index-db) keep living in the instance repo
|
|
7
7
|
// (infra/ is host topology) while scripts/gds/ moves into node_modules/@bongos/core, so each
|
|
8
8
|
// ExecStart runs through infra/core-node.sh, which resolves the script under the instance root OR
|
|
9
9
|
// its node_modules/@bongos/core (both layouts). "Resolves in a consumer layout" is provable from
|