@bongos/core 1.21.105 → 1.21.107
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 +88 -58
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +4 -0
- package/clients/bongos-client/index.cjs +4 -0
- package/clients/bongos-client/index.d.ts +6 -1
- package/clients/bongos-client/index.mjs +4 -0
- package/docs/api/openapi.json +91 -2
- package/docs/api-reference.md +5 -3
- package/docs/copy-inventory.md +368 -366
- package/docs/copy-registry.json +475 -457
- package/docs/design/project-startup-direction.md +14 -0
- package/docs/module-api-changelog.md +4 -0
- package/docs/page-inventory.json +10 -3
- package/docs/page-readings.json +1023 -977
- package/migrations/core_275_claims_auto_pickup.sql +24 -0
- package/modules/government/decision-rules.js +1 -0
- package/modules/lifecycle/autopickup.js +94 -0
- package/modules/lifecycle/db-claims.js +18 -4
- package/modules/lifecycle/routes/claims.js +12 -1
- package/modules/lifecycle/routes/project-settings.js +59 -0
- package/modules/public-landing/public/projects-hall-live.states.json +3 -2
- package/modules/public-landing/public/projects-setup.states.json +91 -0
- package/modules/public-landing/public/projects.html +535 -804
- package/modules/public-landing/public/projects.probes.json +3 -3
- package/modules/public-landing/public/projects.states.json +1 -1
- package/modules/ui-design/kit/fixtures/provisioning-instances-hall-live.json +22 -2
- package/modules/ui-design/kit/fixtures/provisioning-instances-setup.json +195 -0
- package/modules/ui-design/kit/serve.js +22 -4
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +12 -0
- package/scripts/gds/government-walk.js +1 -0
- package/scripts/gds/run-unit-tests.js +3 -0
- package/src/bongos/project-settings.js +79 -0
- package/src/module-api.js +8 -1
- package/tests/autopickup_cap.mjs +236 -0
- package/tests/autopickup_cap_db.mjs +115 -0
- package/tests/cosmos_token_contrast.mjs +10 -18
- package/tests/github_handback_any_device.mjs +4 -3
- package/tests/github_one_trip.mjs +45 -47
- package/tests/github_org_account.mjs +2 -2
- package/tests/github_pick_up.mjs +40 -29
- package/tests/government_act_alone_buildings.mjs +1 -0
- package/tests/onboard.mjs +13 -7
- package/tests/project_invite_ui.mjs +6 -3
- package/tests/project_modules_ui.mjs +3 -3
- package/tests/projects_hub.mjs +8 -9
- package/tests/projects_hub_cloud_hop.mjs +77 -125
- package/tests/projects_hub_dns_ready.mjs +42 -51
- package/tests/projects_hub_pre_uat.mjs +68 -69
- package/tests/public_landing_projects.mjs +45 -102
- package/tests/setup_status_facts.mjs +400 -0
- package/tests/wizard_github_feedback.mjs +90 -87
- package/tests/wizard_one_page.mjs +11 -9
- package/tests/wizard_auto_open.mjs +0 -94
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
-- core_275 a claim can carry the auto_pickup mark
|
|
2
|
+
-- Applied under task 1004677 (BV2.TW19a, ADR 0371 D5/D6).
|
|
3
|
+
--
|
|
4
|
+
-- WHY. The Autobongos tweak lane picks up a submitted page round with nobody at a
|
|
5
|
+
-- terminal, and each pickup costs the project a grade nobody chose to spend. So the
|
|
6
|
+
-- lane claims with a mark, and the SERVER counts marked claims at claim time:
|
|
7
|
+
-- tweak.autopickup_monthly_cap per calendar month, and at most two per round. The
|
|
8
|
+
-- count is read from these rows (the ledger), never from a stored counter.
|
|
9
|
+
--
|
|
10
|
+
-- SHAPE. One nullable boolean. NULL and false both mean "an ordinary claim"; only
|
|
11
|
+
-- true is counted. Nullable with no default, so the column is additive and an
|
|
12
|
+
-- older release that never names it keeps inserting exactly as before.
|
|
13
|
+
--
|
|
14
|
+
-- The partial index serves the two counts (this month's marked claims, and one
|
|
15
|
+
-- round's marked claims), and stays tiny: only marked rows are in it.
|
|
16
|
+
|
|
17
|
+
ALTER TABLE claims ADD COLUMN IF NOT EXISTS auto_pickup boolean;
|
|
18
|
+
|
|
19
|
+
CREATE INDEX IF NOT EXISTS idx_claims_auto_pickup
|
|
20
|
+
ON claims (claimed_at, task_id)
|
|
21
|
+
WHERE auto_pickup IS TRUE;
|
|
22
|
+
|
|
23
|
+
INSERT INTO schema_migrations (version) VALUES ('core_275_claims_auto_pickup')
|
|
24
|
+
ON CONFLICT (version) DO NOTHING;
|
|
@@ -66,6 +66,7 @@ const AREAS = Object.freeze([
|
|
|
66
66
|
today: 'whoever may change the project settings', acts: Object.freeze([
|
|
67
67
|
'PATCH /project-settings/rot-days',
|
|
68
68
|
'PATCH /project-settings/ship-mode',
|
|
69
|
+
'PATCH /project-settings/tweak-autopickup',
|
|
69
70
|
'PATCH /work-categories/:id',
|
|
70
71
|
]) }),
|
|
71
72
|
Object.freeze({ key: 'disputes', name: 'Disputes', gate: 'security.report.adjudicate',
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// modules/lifecycle/autopickup.js — the server's half of tweak auto-pickup
|
|
4
|
+
// (task 1004677 / BV2.TW19a, ADR 0371 D3, D5, D6).
|
|
5
|
+
//
|
|
6
|
+
// The Autobongos tweak lane claims a submitted page round with an `auto_pickup`
|
|
7
|
+
// mark (claims.auto_pickup, migration core_275). The runner is a builder's own
|
|
8
|
+
// process, so the limits on it are NOT left to the runner: claimTask calls
|
|
9
|
+
// autoPickupRefusal inside its transaction and the claim is refused when
|
|
10
|
+
//
|
|
11
|
+
// - the claim is marked but the task is not a page-tweak round (AUTO_PICKUP_NOT_A_TWEAK)
|
|
12
|
+
// - the project has tweak.autopickup off (AUTO_PICKUP_OFF)
|
|
13
|
+
// - this calendar month already holds `cap` marked claims (AUTO_PICKUP_CAP_REACHED)
|
|
14
|
+
// - this round already has two marked claims (AUTO_PICKUP_ROUND_LIMIT)
|
|
15
|
+
//
|
|
16
|
+
// THE LOCK. The count and the claim insert must not interleave with another
|
|
17
|
+
// runner's, or two runners racing for the last slot both read cap-1 and both
|
|
18
|
+
// insert. So the count runs after pg_advisory_xact_lock('page-tweak/autopickup'),
|
|
19
|
+
// one project-wide key, held to the end of claimTask's transaction (the insert
|
|
20
|
+
// commits under it). Only marked claims take the lock; an ordinary claim never
|
|
21
|
+
// waits on it.
|
|
22
|
+
//
|
|
23
|
+
// COUNTED FROM THE LEDGER, never a counter: a stored number drifts the first time
|
|
24
|
+
// a write fails between the claim and the bump. A released claim still counts —
|
|
25
|
+
// the pickup happened and the grade may already have been spent.
|
|
26
|
+
//
|
|
27
|
+
// The mark is a cost brake on a runner the owner chose to run, not a security
|
|
28
|
+
// boundary: a claim without it is an ordinary claim its builder could make by hand.
|
|
29
|
+
|
|
30
|
+
const api = require('../../src/module-api');
|
|
31
|
+
|
|
32
|
+
const PAGE_TWEAK_SOURCE = 'page-tweak';
|
|
33
|
+
const LOCK_KEY = 'page-tweak/autopickup';
|
|
34
|
+
// D6.2: one apply plus one try at the artist's note; a round sent back twice is a
|
|
35
|
+
// disagreement a person should read.
|
|
36
|
+
const MAX_AUTO_APPLIES_PER_ROUND = 2;
|
|
37
|
+
|
|
38
|
+
// The two counts, on any executor (the claim transaction's client, or the pool).
|
|
39
|
+
// Month boundaries are the database's, so every runner and every reader agree.
|
|
40
|
+
const MONTH_COUNT_SQL = `
|
|
41
|
+
SELECT count(*)::int AS n
|
|
42
|
+
FROM claims c JOIN tasks t ON t.id = c.task_id
|
|
43
|
+
WHERE c.auto_pickup IS TRUE
|
|
44
|
+
AND t.source = '${PAGE_TWEAK_SOURCE}'
|
|
45
|
+
AND c.claimed_at >= date_trunc('month', now())`;
|
|
46
|
+
const ROUND_COUNT_SQL = `
|
|
47
|
+
SELECT count(*)::int AS n FROM claims WHERE task_id = $1 AND auto_pickup IS TRUE`;
|
|
48
|
+
|
|
49
|
+
async function countThisMonth(exec = api.pool) {
|
|
50
|
+
const { rows } = await exec.query(MONTH_COUNT_SQL);
|
|
51
|
+
return Number(rows[0] && rows[0].n) || 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function countForRound(exec, taskId) {
|
|
55
|
+
const { rows } = await exec.query(ROUND_COUNT_SQL, [taskId]);
|
|
56
|
+
return Number(rows[0] && rows[0].n) || 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// autoPickupRefusal(client, task, settings) — null when the marked claim may
|
|
60
|
+
// proceed, else the refusal object claimTask throws. `settings` is the resolved
|
|
61
|
+
// { mode, cap }, read BEFORE the transaction opens (the claimPermissionsFor
|
|
62
|
+
// precedent: a settings read is not part of the claim's consistency).
|
|
63
|
+
async function autoPickupRefusal(client, task, settings) {
|
|
64
|
+
if (!task || task.source !== PAGE_TWEAK_SOURCE) {
|
|
65
|
+
return { code: 'AUTO_PICKUP_NOT_A_TWEAK', message: 'Only a page tweak round can be claimed with the auto_pickup mark.' };
|
|
66
|
+
}
|
|
67
|
+
const s = settings || {};
|
|
68
|
+
if (s.mode !== 'on') {
|
|
69
|
+
return { code: 'AUTO_PICKUP_OFF', message: 'Tweak auto-pickup is off for this project, so a submitted page waits for a person.' };
|
|
70
|
+
}
|
|
71
|
+
await client.query('SELECT pg_advisory_xact_lock(hashtext($1))', [LOCK_KEY]);
|
|
72
|
+
const forRound = await countForRound(client, task.id);
|
|
73
|
+
if (forRound >= MAX_AUTO_APPLIES_PER_ROUND) {
|
|
74
|
+
return {
|
|
75
|
+
code: 'AUTO_PICKUP_ROUND_LIMIT', applied: forRound, limit: MAX_AUTO_APPLIES_PER_ROUND,
|
|
76
|
+
message: `This page round was already applied automatically ${forRound} times, so it waits for a person.`,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
const used = await countThisMonth(client);
|
|
80
|
+
if (used >= s.cap) {
|
|
81
|
+
return {
|
|
82
|
+
code: 'AUTO_PICKUP_CAP_REACHED', used, cap: s.cap,
|
|
83
|
+
message: `Auto-pickup has used this month's ${s.cap} rounds, so submitted pages wait for a person until next month.`,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = {
|
|
90
|
+
LOCK_KEY,
|
|
91
|
+
MAX_AUTO_APPLIES_PER_ROUND,
|
|
92
|
+
countThisMonth,
|
|
93
|
+
autoPickupRefusal,
|
|
94
|
+
};
|
|
@@ -37,6 +37,7 @@ const { claimGate, claimPermissionsFor, disambiguateWorktreeName, foldWorktreeNa
|
|
|
37
37
|
const { sealSessionLog } = require('./db-shared.js');
|
|
38
38
|
const { gatingRebaseTasksForBuilder, shouldRefuseClaimResolve } = require('./db-ship.js');
|
|
39
39
|
const { REWARD_SUGGESTION_CAP, rewardGateAssignment } = require('./db-tasks.js');
|
|
40
|
+
const { autoPickupRefusal } = require('./autopickup.js');
|
|
40
41
|
|
|
41
42
|
// -------------------------------------------------------------------------
|
|
42
43
|
// Claims (atomic)
|
|
@@ -99,8 +100,11 @@ function isRebaseGateExempt(task) {
|
|
|
99
100
|
return Boolean(task) && task.kind === 'infra' && Number(task.priority) === 1;
|
|
100
101
|
}
|
|
101
102
|
|
|
102
|
-
async function claimTask({ taskId, builderId, worktreeName, headSha, creatorSessionId, enforceOverlap = false }) {
|
|
103
|
+
async function claimTask({ taskId, builderId, worktreeName, headSha, creatorSessionId, enforceOverlap = false, autoPickup = false }) {
|
|
103
104
|
const heldPermissions = await claimPermissionsFor(builderId); // BV1.R106 — before the tx opens
|
|
105
|
+
// ADR 0371 D5: a marked claim needs the project's switch and cap, read before the
|
|
106
|
+
// tx like the permissions above; the COUNT runs inside it, under the lock.
|
|
107
|
+
const autoPickupSettings = autoPickup ? await api.projectSettings.resolveTweakAutopickup() : null;
|
|
104
108
|
const client = await pool.connect();
|
|
105
109
|
try {
|
|
106
110
|
await client.query('BEGIN');
|
|
@@ -142,7 +146,7 @@ async function claimTask({ taskId, builderId, worktreeName, headSha, creatorSess
|
|
|
142
146
|
}
|
|
143
147
|
|
|
144
148
|
const { rows: taskRows } = await client.query(
|
|
145
|
-
`SELECT id, status, touches, newcomer_friendly, requires_rank, needs_migration, module_key, credits_reward, reward_gate_exempt, est_minutes, kind, goal_id FROM tasks WHERE id = $1 FOR UPDATE`,
|
|
149
|
+
`SELECT id, status, touches, newcomer_friendly, requires_rank, needs_migration, module_key, credits_reward, reward_gate_exempt, est_minutes, kind, goal_id, source FROM tasks WHERE id = $1 FOR UPDATE`,
|
|
146
150
|
[taskId]
|
|
147
151
|
);
|
|
148
152
|
if (taskRows.length === 0) {
|
|
@@ -350,6 +354,14 @@ async function claimTask({ taskId, builderId, worktreeName, headSha, creatorSess
|
|
|
350
354
|
}
|
|
351
355
|
}
|
|
352
356
|
|
|
357
|
+
// ADR 0371 D5/D6 (task 1004677): the auto_pickup mark. The cap and the per-round
|
|
358
|
+
// limit are counted under a project-wide advisory lock that this transaction
|
|
359
|
+
// holds through the insert below, so two runners cannot both take the last slot.
|
|
360
|
+
if (autoPickup) {
|
|
361
|
+
const refusal = await autoPickupRefusal(client, task, autoPickupSettings);
|
|
362
|
+
if (refusal) throw refusal;
|
|
363
|
+
}
|
|
364
|
+
|
|
353
365
|
// Pre-allocate a migration number if the task signals it'll add one.
|
|
354
366
|
// Trigger: the tasks.needs_migration boolean (migration 081, touches[]
|
|
355
367
|
// cleanup [1/8] / task 876). Replaced the old touches[]-contains-'migrations/'
|
|
@@ -396,9 +408,11 @@ async function claimTask({ taskId, builderId, worktreeName, headSha, creatorSess
|
|
|
396
408
|
finalWorktreeName = disambiguateWorktreeName(finalWorktreeName, taken);
|
|
397
409
|
}
|
|
398
410
|
|
|
411
|
+
// The column is named only on a marked claim, so an ordinary claim's insert is
|
|
412
|
+
// byte-identical to before core_275.
|
|
399
413
|
const insertClaim = await client.query(
|
|
400
|
-
`INSERT INTO claims (task_id, builder_id, worktree_name, requested_worktree_name, head_sha, reserved_migration_number, creator_session_id)
|
|
401
|
-
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
414
|
+
`INSERT INTO claims (task_id, builder_id, worktree_name, requested_worktree_name, head_sha, reserved_migration_number, creator_session_id${autoPickup ? ', auto_pickup' : ''})
|
|
415
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7${autoPickup ? ', TRUE' : ''})
|
|
402
416
|
RETURNING id, task_id, builder_id, worktree_name, requested_worktree_name, claimed_at, head_sha, reserved_migration_number`,
|
|
403
417
|
[taskId, builderId, finalWorktreeName, requestedWorktreeName, headSha ?? null, reservedMigrationNumber, creatorSessionId ?? null]
|
|
404
418
|
);
|
|
@@ -276,8 +276,12 @@ module.exports = function buildClaimsRouter() {
|
|
|
276
276
|
// an interactive single-human claim only WARNS (git merge is the real
|
|
277
277
|
// collision detector — ADR 0017).
|
|
278
278
|
enforce_touches: { type: 'boolean' },
|
|
279
|
+
// ADR 0371 D5 (task 1004677): the Autobongos tweak lane's mark. The server
|
|
280
|
+
// counts marked claims against the project's monthly cap and the per-round
|
|
281
|
+
// limit; see modules/lifecycle/autopickup.js.
|
|
282
|
+
auto_pickup: { type: 'boolean' },
|
|
279
283
|
})) return;
|
|
280
|
-
const { task_id: taskId, worktree_name: worktreeName, head_sha: headSha, bind_session: bindSession, enforce_touches: enforceTouches } = req.body || {};
|
|
284
|
+
const { task_id: taskId, worktree_name: worktreeName, head_sha: headSha, bind_session: bindSession, enforce_touches: enforceTouches, auto_pickup: autoPickup } = req.body || {};
|
|
281
285
|
// Belt-and-braces — task_id must coerce to a finite number. Older calls
|
|
282
286
|
// sent string ints (Number.isFinite passes both); reject NaN/garbage.
|
|
283
287
|
if (!Number.isFinite(Number(taskId))) {
|
|
@@ -291,6 +295,7 @@ module.exports = function buildClaimsRouter() {
|
|
|
291
295
|
headSha: headSha ?? null,
|
|
292
296
|
creatorSessionId: resolveCreatorSessionId(bindSession, req.gdsSession?.session_id),
|
|
293
297
|
enforceOverlap: enforceTouches === true,
|
|
298
|
+
autoPickup: autoPickup === true,
|
|
294
299
|
});
|
|
295
300
|
const { just_unlocked: justUnlocked, overlap_warning: overlapWarning, sibling_overlap_warning: siblingOverlapWarning, ...claim } = claimResult;
|
|
296
301
|
const task = await db.getTask(Number(taskId));
|
|
@@ -375,6 +380,12 @@ module.exports = function buildClaimsRouter() {
|
|
|
375
380
|
// block, not an authorization refusal). The refusal object already
|
|
376
381
|
// carries `message` + `hint`, so no extra hint-building step needed.
|
|
377
382
|
err.code === 'RELEVANCE_REVIEW_PENDING' ? 409 :
|
|
383
|
+
// ADR 0371 D5/D6: a marked auto-pickup claim the project's switch, monthly
|
|
384
|
+
// cap or per-round limit refuses. The round waits for a person.
|
|
385
|
+
err.code === 'AUTO_PICKUP_NOT_A_TWEAK' ? 409 :
|
|
386
|
+
err.code === 'AUTO_PICKUP_OFF' ? 409 :
|
|
387
|
+
err.code === 'AUTO_PICKUP_CAP_REACHED' ? 409 :
|
|
388
|
+
err.code === 'AUTO_PICKUP_ROUND_LIMIT' ? 409 :
|
|
378
389
|
500;
|
|
379
390
|
// V4.R14 (#952): a TASK_NOT_READY 409 names the way forward instead of
|
|
380
391
|
// leaving the caller to discover the promote route by spelunking (#506).
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
const express = require('express');
|
|
32
32
|
const api = require('../../../src/module-api');
|
|
33
33
|
const goalCategory = require('../goal-category');
|
|
34
|
+
const autopickup = require('../autopickup');
|
|
34
35
|
|
|
35
36
|
const log = api.logger('lifecycle');
|
|
36
37
|
|
|
@@ -380,6 +381,64 @@ module.exports = function buildProjectSettingsRouter() {
|
|
|
380
381
|
}
|
|
381
382
|
});
|
|
382
383
|
|
|
384
|
+
// --- tweak auto-pickup (task 1004677, ADR 0371 D3/D5) ----------------------
|
|
385
|
+
//
|
|
386
|
+
// GET /project-settings/tweak-autopickup — the switch, the monthly cap, and how
|
|
387
|
+
// many rounds the lane has picked up this calendar month (counted from marked
|
|
388
|
+
// claims, never a stored counter).
|
|
389
|
+
//
|
|
390
|
+
// rank: any signed-in builder. The runner reads it before it tries a round, and
|
|
391
|
+
// the studio shows the count; it carries no reward internals or file paths.
|
|
392
|
+
async function autopickupBody() {
|
|
393
|
+
const resolved = await api.projectSettings.resolveTweakAutopickup();
|
|
394
|
+
const used = await autopickup.countThisMonth();
|
|
395
|
+
return {
|
|
396
|
+
mode: resolved.mode,
|
|
397
|
+
cap: resolved.cap,
|
|
398
|
+
used_this_month: used,
|
|
399
|
+
remaining_this_month: Math.max(0, resolved.cap - used),
|
|
400
|
+
per_round_limit: autopickup.MAX_AUTO_APPLIES_PER_ROUND,
|
|
401
|
+
source: resolved.source,
|
|
402
|
+
invalid: resolved.invalid,
|
|
403
|
+
sentence: api.projectSettings.describeTweakAutopickup(resolved),
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
router.get('/project-settings/tweak-autopickup', api.requireBuilder, async (req, res) => {
|
|
408
|
+
try {
|
|
409
|
+
res.set('Cache-Control', 'no-store');
|
|
410
|
+
res.json(await autopickupBody());
|
|
411
|
+
} catch (err) {
|
|
412
|
+
log.error(`GET /project-settings/tweak-autopickup: ${err && err.message}`);
|
|
413
|
+
res.fail('project_settings_read_failed', { status: 500, message: 'internal error' });
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
// PATCH /project-settings/tweak-autopickup — body { mode?: 'off' | 'on', cap?: n }.
|
|
418
|
+
//
|
|
419
|
+
// rank: project.settings.manage (metic+, government_010), the same atom as the
|
|
420
|
+
// other writes on this page. Each field is validated by the resolver's own parser,
|
|
421
|
+
// and both are checked before either is written, so a half-valid body writes nothing.
|
|
422
|
+
router.patch('/project-settings/tweak-autopickup', api.requireBuilder, api.requirePermission('project.settings.manage'), api.requireActAlone('rules'), async (req, res) => {
|
|
423
|
+
if (api.validateOrRespond(req, res, { mode: { type: 'string' }, cap: { type: 'number' } })) return;
|
|
424
|
+
const body = req.body || {};
|
|
425
|
+
if (body.mode == null && body.cap == null) {
|
|
426
|
+
return res.fail('bad_tweak_autopickup', { status: 400, message: 'send mode, cap, or both' });
|
|
427
|
+
}
|
|
428
|
+
const mode = body.mode == null ? null : api.projectSettings.parseAutopickup(body.mode);
|
|
429
|
+
if (mode && !mode.mode) return res.fail('bad_tweak_autopickup', { status: 400, message: `mode: ${mode.reason}` });
|
|
430
|
+
const cap = body.cap == null ? null : api.projectSettings.parseAutopickupCap(body.cap);
|
|
431
|
+
if (cap && cap.cap == null) return res.fail('bad_tweak_autopickup', { status: 400, message: `cap: ${cap.reason}` });
|
|
432
|
+
try {
|
|
433
|
+
if (mode) await api.projectSettings.set(api.projectSettings.KEYS.TWEAK_AUTOPICKUP, mode.mode, req.builder.id);
|
|
434
|
+
if (cap) await api.projectSettings.set(api.projectSettings.KEYS.TWEAK_AUTOPICKUP_CAP, cap.cap, req.builder.id);
|
|
435
|
+
res.json({ ok: true, ...(await autopickupBody()) });
|
|
436
|
+
} catch (err) {
|
|
437
|
+
log.error(`PATCH /project-settings/tweak-autopickup: ${err && err.message}`);
|
|
438
|
+
res.fail('project_settings_write_failed', { status: 500, message: 'internal error' });
|
|
439
|
+
}
|
|
440
|
+
});
|
|
441
|
+
|
|
383
442
|
return router;
|
|
384
443
|
};
|
|
385
444
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"_": "The create wizard done panel once the hall answers (task 1004503): the same walk as projects.states.json in-new-done, with the instance list aliased so the project just filed (id 102) is live and verified up. The invite box
|
|
2
|
+
"_": "The create wizard done panel once the hall answers (task 1004503): the same walk as projects.states.json in-new-done, with the instance list aliased so the project just filed (id 102) is live and verified up, with its GitHub app approved, installed and signed in (since task 1004683 part 03 says it is alive only once every required fact is done). The invite box and the Enter Genesis door open only now; in-new-done in the main file pictures it shut while the project is set up. Rendered by name: node modules/ui-design/kit/render.js --states modules/public-landing/public/projects-hall-live.states.json",
|
|
3
3
|
"page": "/projects",
|
|
4
4
|
"surface": "public-landing",
|
|
5
5
|
"modes": [
|
|
@@ -131,7 +131,8 @@
|
|
|
131
131
|
"#panel-done",
|
|
132
132
|
"#wizInvite",
|
|
133
133
|
"#wizInviteWho",
|
|
134
|
-
"#
|
|
134
|
+
"#doneAlive",
|
|
135
|
+
"#enterGenesis"
|
|
135
136
|
],
|
|
136
137
|
"hidden": [
|
|
137
138
|
"#hop",
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_": "Part 03 after Create, the five scenarios of the design of record docs/design/mocks/day-night-rooms/setup-status.html (task 1004683): the same page and stub, the instance list aliased to one project per scenario, each opened by URL the way the GitHub return route lands a founder (?view=new&id=<project>). The GitHub halves of each owner read come from the REAL projections (see the fixture's note). The room follows the viewer's clock, so these renders picture whichever room the machine's clock gives, and the stub serves a local address with no apex base, so the Approve fact pictures its local-platform branch (GitHub cannot reach a local platform) rather than Connect GitHub. The day and night shots attached to the task were taken with the browser's timezone moved and the apex stamped. Rendered by name: node modules/ui-design/kit/render.js --states modules/public-landing/public/projects-setup.states.json",
|
|
3
|
+
"page": "/projects",
|
|
4
|
+
"surface": "public-landing",
|
|
5
|
+
"modes": [
|
|
6
|
+
"dark"
|
|
7
|
+
],
|
|
8
|
+
"modeQuery": false,
|
|
9
|
+
"stub": {
|
|
10
|
+
"fixtures": {
|
|
11
|
+
"provisioning-instances": "provisioning-instances-setup"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"ignoreRequests": [
|
|
15
|
+
"/api/(gds|bongos)/me$",
|
|
16
|
+
"/my-projects",
|
|
17
|
+
"/github/orgs",
|
|
18
|
+
"/env-manifest$"
|
|
19
|
+
],
|
|
20
|
+
"ignoreConsole": [
|
|
21
|
+
"/api/(gds|bongos)/me",
|
|
22
|
+
"\\b401\\b",
|
|
23
|
+
"\\b404\\b",
|
|
24
|
+
"Unauthorized"
|
|
25
|
+
],
|
|
26
|
+
"ignoreControls": [
|
|
27
|
+
".skip",
|
|
28
|
+
".vh"
|
|
29
|
+
],
|
|
30
|
+
"states": {
|
|
31
|
+
"setup-just-created": {
|
|
32
|
+
"auth": true,
|
|
33
|
+
"url": "/projects?view=new&id=201",
|
|
34
|
+
"actions": [["wait", 1500]],
|
|
35
|
+
"expect": {
|
|
36
|
+
"visible": ["#panel-done", "#setupNow", "#homeFacts", "#ghFacts", "#hopLink", "#homeFacts [data-fact=\"server\"].now"],
|
|
37
|
+
"hidden": ["#wizParts", "#hop", "#doneAlive", "#aaPick"],
|
|
38
|
+
"text": [["#donePartT", "Getting kestrel ready"], ["#ghState", "1 of 6 done"]]
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"setup-waiting-on-github": {
|
|
42
|
+
"auth": true,
|
|
43
|
+
"url": "/projects?view=new&id=202",
|
|
44
|
+
"actions": [["wait", 1500]],
|
|
45
|
+
"expect": {
|
|
46
|
+
"visible": ["#panel-done", "#homeFacts [data-fact=\"answers\"].now"],
|
|
47
|
+
"hidden": ["#hop", "#doneAlive", "#aaPick"],
|
|
48
|
+
"text": [["#ghState", "2 of 6 done"]]
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"setup-installing": {
|
|
52
|
+
"auth": true,
|
|
53
|
+
"url": "/projects?view=new&id=203",
|
|
54
|
+
"actions": [["wait", 1500]],
|
|
55
|
+
"expect": {
|
|
56
|
+
"visible": ["#panel-done", "#ghFacts [data-fact=\"install\"].you"],
|
|
57
|
+
"hidden": ["#hop", "#doneAlive"],
|
|
58
|
+
"text": [["#ghState", "4 of 6 done"]]
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"setup-stopped": {
|
|
62
|
+
"auth": true,
|
|
63
|
+
"url": "/projects?view=new&id=204",
|
|
64
|
+
"actions": [["wait", 1500]],
|
|
65
|
+
"expect": {
|
|
66
|
+
"visible": ["#panel-done", "#ghFacts [data-fact=\"install\"].bad [data-action=\"pick-up\"]"],
|
|
67
|
+
"hidden": ["#hop", "#doneAlive"],
|
|
68
|
+
"text": [["#ghState", "5 of 6 done"]]
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"setup-all-done": {
|
|
72
|
+
"auth": true,
|
|
73
|
+
"url": "/projects?view=new&id=205",
|
|
74
|
+
"actions": [["wait", 1500]],
|
|
75
|
+
"expect": {
|
|
76
|
+
"visible": ["#panel-done", "#doneAlive", "#enterGenesis"],
|
|
77
|
+
"hidden": ["#hop", "#hopLink"],
|
|
78
|
+
"text": [["#ghState", "ready ✓"], ["#done-h", "wren is alive."], ["#enterGenesis", "Enter Genesis"]]
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"setup-cloud-hop-open": {
|
|
82
|
+
"auth": true,
|
|
83
|
+
"url": "/projects?view=new&id=201",
|
|
84
|
+
"actions": [["wait", 1200], ["click", "#hopLink"], ["wait", 600]],
|
|
85
|
+
"expect": {
|
|
86
|
+
"visible": ["#hop", "#hopCanvas"],
|
|
87
|
+
"attr": [["#hopLink", "aria-expanded", "true"]]
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|