review access: guest-play apps rejected by Play as a login wall (empty name field, disabled Continue, a code link on the first screen): check warns for a Play app with a first-run gate or IAP and no reviewAccess.instructions; with guest steps the play-sign-in-details plan declares one entry without credentials, the dialog's required full-access box as the owner's step; store-pitfalls 73
This commit is contained in:
parent
d6070cc185
commit
824758179b
11 changed files with 202 additions and 15 deletions
|
|
@ -209,13 +209,34 @@ function adsDeclaration(config: ShipConfig, p: PlanIds): Part {
|
|||
};
|
||||
}
|
||||
|
||||
/** Play's Add instructions dialog: "Any other information required to access your app" holds at most 500 characters. */
|
||||
export const PLAY_ACCESS_INFO_MAX = 500;
|
||||
/** The name of the one entry a guest-play app declares (no account, no credentials). */
|
||||
export const GUEST_ENTRY_NAME = 'Guest play (no account needed)';
|
||||
/** The Add instructions dialog's required box: an agreement, ticked by the owner only. */
|
||||
export const PLAY_FULL_ACCESS_BOX = 'Sign in details in this declaration provide full access to all the features and content within this app, including premium or paid content';
|
||||
|
||||
function signInDetails(config: ShipConfig, p: PlanIds): Part {
|
||||
const ra = config.reviewAccess;
|
||||
const all = 'All functionality in my app is available without any access restrictions', some = 'All or some functionality in my app is restricted';
|
||||
const out: PlanAnswer[] = [ra ? ans('access', 'Is any functionality restricted (sign-in, membership, location)?', ra.signInRequired, 'certain', 'reviewAccess.signInRequired', { control: 'radio', action: 'pick', label: ra.signInRequired ? some : all, where: 'Sign in details (App access)' })
|
||||
: ans('access', 'Is any functionality restricted (sign-in, membership, location)?', null, 'ask-owner', 'reviewAccess.signInRequired', { control: 'radio', where: 'Sign in details', note: 'Set reviewAccess { signInRequired } (review-access skill).' })];
|
||||
if (ra?.signInRequired) {
|
||||
out.push(ra.instructions ? ans('instructions', 'Instructions for the reviewer', ra.instructions, 'certain', 'reviewAccess.instructions', { control: 'text', action: 'type', label: 'Any other information required to access your app', where: 'Add instructions' })
|
||||
const info = 'Any other information required to access your app';
|
||||
// a guest-play app with reviewer steps (signInRequired false + instructions): Play rejected such a game as a login
|
||||
// wall ("provide valid login credentials") while it was declared unrestricted, so it is declared restricted with
|
||||
// one entry that has no credentials and says how to get in as a guest
|
||||
const guest = !!ra && !ra.signInRequired && !!ra.instructions?.trim();
|
||||
const restricted = !!ra && (ra.signInRequired || guest);
|
||||
const q = 'Is any functionality restricted (sign-in, membership, location)?';
|
||||
const out: PlanAnswer[] = [ra ? ans('access', q, restricted, 'certain', guest ? 'reviewAccess.instructions (guest steps, no sign-in)' : 'reviewAccess.signInRequired', { control: 'radio', action: 'pick', label: restricted ? some : all, where: 'Sign in details (App access)',
|
||||
...(guest ? { note: 'No sign-in, but guest steps: answered restricted so the reviewer reads them (Play rejected a guest-play game declared unrestricted as a login wall).' } : {}) })
|
||||
: ans('access', q, null, 'ask-owner', 'reviewAccess.signInRequired', { control: 'radio', where: 'Sign in details', note: 'Set reviewAccess { signInRequired } (review-access skill).' })];
|
||||
const long = (t: string) => t.length > PLAY_ACCESS_INFO_MAX ? { note: `${t.length} characters: Play takes at most ${PLAY_ACCESS_INFO_MAX}; shorten reviewAccess.instructions.` } : {};
|
||||
if (guest) {
|
||||
const steps = ra!.instructions!.trim();
|
||||
out.push(ans('entryName', 'Name of the instructions entry', GUEST_ENTRY_NAME, 'certain', 'reviewAccess.signInRequired false', { control: 'text', action: 'type', label: GUEST_ENTRY_NAME, where: 'Add instructions: Name' }));
|
||||
out.push(ans('credentials', 'Username and password', null, 'certain', 'reviewAccess.signInRequired false', { control: 'text', where: 'Add instructions: Username, Password', text: 'leave both empty (no account)', note: 'Guest play: no credentials exist; type nothing into Username or Password.' }));
|
||||
out.push(ans('instructions', 'Instructions for the reviewer', steps, steps.length > PLAY_ACCESS_INFO_MAX ? 'owner-check' : 'certain', 'reviewAccess.instructions', { control: 'text', action: 'type', label: info, where: 'Add instructions: Any other information', ...long(steps) }));
|
||||
} else if (ra?.signInRequired) {
|
||||
out.push(ra.instructions ? ans('instructions', 'Instructions for the reviewer', ra.instructions, 'certain', 'reviewAccess.instructions', { control: 'text', action: 'type', label: info, where: 'Add instructions', ...long(ra.instructions) })
|
||||
: ans('instructions', 'Instructions for the reviewer', null, 'ask-owner', 'reviewAccess.instructions', { note: 'Set reviewAccess.instructions (how to sign in and reach the main features).' }));
|
||||
// with reviewDemoAccount in .storebound/credentials.json the agent types it (never printed: not in chat, logs, the
|
||||
// plan or a commit); without it the owner types the username and password (or adds it there first)
|
||||
|
|
@ -228,22 +249,30 @@ function signInDetails(config: ShipConfig, p: PlanIds): Part {
|
|||
control: 'text', where: 'Add instructions: Username, Password',
|
||||
note: `reviewDemoAccount: ${p.demoAccount === undefined ? 'not checked' : 'MISSING'}. The owner adds it to .storebound/credentials.json before the run (then the agent types it, never printed), or types the username and password into the card themselves. storebound never prints them.` }));
|
||||
}
|
||||
// the dialog's required declaration box: an agreement, so the owner ticks it (agents never tick declarations)
|
||||
if (restricted) out.push(ans('fullAccess', 'Do these sign in details give full access to every feature and content, including premium or paid content?', null, 'agreement', 'Play Add instructions dialog (required)', { control: 'checkbox', label: PLAY_FULL_ACCESS_BOX, where: 'Add instructions dialog, required box' }));
|
||||
const add = 'Add instructions';
|
||||
return {
|
||||
title: 'Play Console: Sign in details (App access)',
|
||||
start: start(config, p, 'app-content/testing-credentials', appContentReach('Sign in details')),
|
||||
steps: steps([
|
||||
{ text: `Open App content > Sign in details: ${start(config, p, 'app-content/testing-credentials', []).url}` },
|
||||
{ text: 'Pick whether any functionality is restricted (material radio: JS click on the inner [role=radio]).', answers: ['access'] },
|
||||
guest && { text: `Guest steps (no sign-in): press "${add}", type the Name "${GUEST_ENTRY_NAME}", leave Username and Password empty, and type reviewAccess.instructions into "${info}" (at most ${PLAY_ACCESS_INFO_MAX} characters).`, click: [add], answers: ['entryName', 'credentials', 'instructions'] },
|
||||
ra?.signInRequired && { text: p.demoAccount
|
||||
? 'Restricted: press "Add instructions", type the instructions, then type the Username and Password from .storebound/credentials.json (reviewDemoAccount; click each field and type: never echo them in chat or logs).'
|
||||
: 'Restricted: press "Add instructions", type the instructions; the Username and Password are the owner\'s (no reviewDemoAccount in .storebound/credentials.json: in the owner batch).', click: ['Add instructions'], answers: ['instructions', 'credentials'] },
|
||||
? `Restricted: press "${add}", type the instructions, then type the Username and Password from .storebound/credentials.json (reviewDemoAccount; click each field and type: never echo them in chat or logs).`
|
||||
: `Restricted: press "${add}", type the instructions; the Username and Password are the owner's (no reviewDemoAccount in .storebound/credentials.json: in the owner batch).`, click: [add], answers: ['instructions', 'credentials'] },
|
||||
restricted && { text: `Leave the required box "${PLAY_FULL_ACCESS_BOX}" unticked and stop: the owner ticks it (a declaration). Then press "Add" (closes the dialog; the entry is listed).`, click: ['Add'], answers: ['fullAccess'] },
|
||||
{ text: DECLARATION_SAVE },
|
||||
{ text: 'Verify: read the page text and pipe it to `storebound console verify play-sign-in-details --from-text -`.' },
|
||||
]),
|
||||
answers: out,
|
||||
...declarationButtons('Sign in details', [{ button: 'Add instructions', class: 'navigation', where: 'Sign in details: opens the instructions dialog' }]),
|
||||
uiFacts: ['Verified 2026-10-12: the Sign in details card (App access) is /app-content/testing-credentials.', 'Credentials are never in the config, the plan or chat: the agent types them from .storebound/credentials.json (reviewDemoAccount) without printing them; without that entry the owner types them.', PLAY_MATERIAL_FACT],
|
||||
verify: pageVerify('play-sign-in-details', ['The selected radio matches reviewAccess.signInRequired; with a sign-in, one set of instructions is listed.']),
|
||||
...declarationButtons('Sign in details', [{ button: add, class: 'navigation', where: 'Sign in details: opens the instructions dialog' },
|
||||
...(restricted ? [{ button: 'Add', class: 'navigation', where: 'Add instructions dialog: lists the entry on the card (nothing is stored before Save)' }] : [])]),
|
||||
uiFacts: ['Verified 2026-10-12: the Sign in details card (App access) is /app-content/testing-credentials.', 'Credentials are never in the config, the plan or chat: the agent types them from .storebound/credentials.json (reviewDemoAccount) without printing them; without that entry the owner types them.',
|
||||
`The Add instructions dialog: Name, Username, Password, "${info}" (at most ${PLAY_ACCESS_INFO_MAX} characters) and the required box "${PLAY_FULL_ACCESS_BOX}" (the owner's).`,
|
||||
'A guest-play game declared "no restrictions" was rejected as a login wall (empty name field, Continue disabled, an "I have a code" link on the first screen): with guest steps the card says restricted with one entry without credentials.', PLAY_MATERIAL_FACT],
|
||||
verify: pageVerify('play-sign-in-details', [guest ? `Restricted is selected; one entry "${GUEST_ENTRY_NAME}" with no username or password is listed.` : 'The selected radio matches reviewAccess.signInRequired; with a sign-in, one set of instructions is listed.']),
|
||||
guidance: [`Open: Policy and programs > App content > Sign in details (App access): ${start(config, p, 'app-content/testing-credentials', []).url}`],
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue