From 4d21e834a350b17a1b688c389ad2619e08b59c1c Mon Sep 17 00:00:00 2001 From: EMRG Evolution Date: Thu, 5 Nov 2026 15:31:49 +0800 Subject: [PATCH] emrg: the ios-app template looks up what the platform can do --- emrg/server/ios_app_prompt.md | 11 ++++++ tests/test_prompt_templates.py | 68 ++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/emrg/server/ios_app_prompt.md b/emrg/server/ios_app_prompt.md index 44783aea..3bbcbd1b 100644 --- a/emrg/server/ios_app_prompt.md +++ b/emrg/server/ios_app_prompt.md @@ -202,6 +202,17 @@ Write the product as the four or five segments a user passes through, in the ord Order the screens by the order a user uses them, not by the order the code is organised in. Where the order is a preference, the user may choose it — but content is not hidden behind a switch: a screen the user cannot reach is a screen the app does not have. +#### 3.4 What the platform can do is looked up, not assumed + +A feasibility conclusion decides a direction and a design, so it is the one claim in this task that may not be made from memory. The inception record is where a direction's shape is fixed, and a wrong answer here is paid for by every later phase. + +- **Ask the platform's own documentation, not a recollection of it.** On-device models, frameworks and newly shipped APIs change between releases. A direction refused on a remembered limit has been refused for a fact that may no longer hold, and the refusal is indistinguishable in the record from one that was measured. +- **A development machine's limit is not the user's device's.** What refuses to run here is a statement about this machine and about the SDK it happens to carry, never about the devices the app ships to. +- **"It cannot be built here" is not "it cannot be done".** CI builds the matrix this host cannot. Ask what CI can build before narrowing the product to the local toolchain, and do not assert what that costs — an unpriced impression is what turns a buildable direction into an abandoned one. +- **A dependency that raises the minimum OS version is a product decision, not a technical one.** It decides which devices can install the app, so it goes to the host with the numbers: the target today, the target the dependency forces, and what that leaves out. No round takes it on the host's behalf. +- **A degraded implementation is not the feature.** When the documented way turns out to be unavailable, the feasibility question is asked again rather than a weaker version of the core shipped as though it were the same thing — a downgrade is a missing segment (§3.1) wearing the core's name. +- **State the conclusion so the host can repeat it back.** One sentence, in the words a user of the app would use, is what makes a feasibility answer checkable by the person who carries the cost of being wrong about it. + --- ### 4. Phase 4 — Implementation diff --git a/tests/test_prompt_templates.py b/tests/test_prompt_templates.py index 5de05c46..69bcd6ec 100644 --- a/tests/test_prompt_templates.py +++ b/tests/test_prompt_templates.py @@ -3296,3 +3296,71 @@ def test_the_claim_provenance_rule_lives_in_the_section_that_writes_into_a_proje f"the provenance rule is stated {text.count('says who decided it')} times in " "open_source_prompt.md; this template's own rule is that a fact lives in exactly one place" ) + + +# ── the ios-app template's platform-feasibility rules ─────────────────────────────────────── +# +# A feasibility conclusion decides a direction and a design, so it is the claim this template +# can least afford to leave to memory. Measured on master `6f233a51`: the template answered +# zero for `official doc`, `documentation`, `developer.apple`, `deployment target`, +# `minimum os`, `CI` and `downgrade`, while the installation's own block for this task carried +# every one of them as general method — the single concept of fifteen the two did not share. +# These pins hold the section that now carries them, and the control below keeps the pin from +# being satisfied by a section that has been emptied. + +_IOS_FEASIBILITY_HEADING = "#### 3.4 What the platform can do is looked up, not assumed" +_IOS_FEASIBILITY_ENDS_AT = "### 4. Phase 4" + +IOS_FEASIBILITY_PHRASES = ( + "Ask the platform's own documentation", + "not the user's device's", + 'is not "it cannot be done"', + "raises the minimum OS version is a product decision", + "A degraded implementation is not the feature", + "repeat it back", +) + + +def _ios_feasibility_section(text: str) -> str: + return _bounded_section(text, _IOS_FEASIBILITY_HEADING, _IOS_FEASIBILITY_ENDS_AT) + + +def test_the_ios_app_template_answers_a_capability_question_from_the_platform() -> None: + """§3.4 must send a capability question to the platform, to CI and to the host. + + Not decoration: without this section the task decides what is buildable from what it + remembers, and the two ways that goes wrong are both silent. A remembered limit refuses a + direction on a fact that may no longer hold, and the refusal is indistinguishable in the + record from one that was measured; a limit of this development machine is read as a limit + of the user's device, which narrows the product to the local toolchain and to nothing real. + """ + text = _IOS_TEMPLATE.read_text(encoding="utf-8") + section = _ios_feasibility_section(text) + missing = _missing_phrases(section, IOS_FEASIBILITY_PHRASES) + assert not missing, ( + f"ios_app_prompt.md §3.4 no longer answers a capability question: {missing}. Without " + "these the section states a subject and gives the reader nothing to do with it." + ) + + # One home: a rule stated twice leaves a reader holding two answers with no way to choose. + assert text.count("Ask the platform's own documentation") == 1, ( + "the platform-lookup rule is stated " + f"{text.count(chr(65) + 'sk the platform' + chr(39) + 's own documentation')} times in " + "ios_app_prompt.md; this template's own rule is that a fact lives in exactly one place" + ) + + +def test_the_ios_feasibility_pin_answers_both_ways() -> None: + """The control: a section that has lost a rule reads as missing, not as passing. + + Without it, a section emptied of its content and a reader pointed at the wrong region read + the same as a section that still carries the rule — which is the defect the bounded-section + helper exists to prevent, one level up. + """ + section = _ios_feasibility_section(_IOS_TEMPLATE.read_text(encoding="utf-8")) + for phrase in IOS_FEASIBILITY_PHRASES: + stripped = section.replace(phrase, "") + assert phrase in _missing_phrases(stripped, IOS_FEASIBILITY_PHRASES), ( + f"deleting {phrase!r} from §3.4 still reads as present, so the pin above would " + "stay green on a section that had lost the rule" + )