mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-21 10:36:27 +03:00
Stop losing DESIGN.md and native platform refs across init
Bugbot flagged the "resume without rerunning context.mjs" instruction after init. It is right, and the gap is wider than the platform half it named: context.mjs has two output branches, and the no-PRODUCT.md branch omits DESIGN.md, the native platform references, and the unrecognized `## Platform` warning. Because the skill never reruns the script once init writes PRODUCT.md, whatever that first run withheld is gone for the whole session. A greenfield iOS project would be designed without reference/ios.md ever loading, and a project carrying DESIGN.md without PRODUCT.md never saw its own design system. The two halves need different fixes. DESIGN.md is authority in its own right and does not depend on PRODUCT.md existing, so context.mjs now emits it on both branches. Platform is unknowable before PRODUCT.md exists, so no change to the script can recover it; init.md, the one step that learns the answer, now loads ios.md / android.md / both right after recording a native platform, and SKILL.src.md says so where it tells the agent not to rerun. Verified end to end against a temp project on both branches. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -74,7 +74,7 @@ Routing: <!-- rule:skill-routing -->
|
||||
- **Otherwise:** treat the request as general design work. Missing PRODUCT.md routes through init; new surfaces and replacement worlds use new-work.
|
||||
- `teach` aliases `init`. `craft` is a deprecated alias for ordinary new-work and adds nothing. `shape` owns task discovery, then enters new-work only for visual-world and surface-concept decisions.
|
||||
|
||||
After init writes PRODUCT.md, resume without rerunning `context.mjs`.
|
||||
After init writes PRODUCT.md, resume without rerunning `context.mjs`; init loads the native platform reference itself when the platform it recorded is `ios`, `android`, or `adaptive`.
|
||||
|
||||
**Pin / Unpin:** `node {{scripts_path}}/pin.mjs <pin|unpin> <command>` creates or removes a standalone `{{command_prefix}}<command>` shortcut. Report the script's result concisely; relay stderr verbatim on error.
|
||||
|
||||
|
||||
@@ -92,6 +92,8 @@ web
|
||||
|
||||
Platform is the bare value `web`, `ios`, `android`, or `adaptive`. Preserve useful legacy headings. New files go at `PROJECT_ROOT/PRODUCT.md`; otherwise update the resolved file. Write it before any visual-world or surface-concept work.
|
||||
|
||||
When the platform you just recorded is `ios`, `android`, or `adaptive`, load [ios.md](ios.md), [android.md](android.md), or both before any design work. On a project that had no PRODUCT.md, context.mjs could not know the platform and so never loaded them; init is the only place that learns the answer.
|
||||
|
||||
### Completion gate
|
||||
|
||||
Before loading new-work or resuming shape/build, verify that PRODUCT.md exists at the resolved path and contains the confirmed product record. If the file is absent, init is incomplete. Do not substitute interview notes, a planning packet, or later design prose for the file.
|
||||
@@ -111,4 +113,4 @@ Recommend the next action from the actual project state:
|
||||
- Existing surface needing work: name the most relevant scoped command.
|
||||
- Web project ready for visual iteration: `/impeccable live` when configured.
|
||||
|
||||
If init was invoked by another request, resume without rerunning context.mjs; new-work owns later visual decisions.
|
||||
If init was invoked by another request, resume without rerunning context.mjs; the native reference above is the one thing that run could not have given you, and new-work owns later visual decisions.
|
||||
|
||||
@@ -1124,6 +1124,13 @@ async function cli() {
|
||||
'must finish reference/init.md for PRODUCT.md, then reference/new-work.md establishes the world and surface. Scoped ' +
|
||||
'fixes to existing code do not need the new-surface flow.',
|
||||
];
|
||||
// DESIGN.md is authority in its own right and does not depend on
|
||||
// PRODUCT.md existing. Withholding it here used to lose it for the whole
|
||||
// session: the skill resumes after init writes PRODUCT.md without
|
||||
// rerunning this script, so the hasProduct branch below never runs.
|
||||
if (ctx.hasDesign) {
|
||||
parts.push(`# DESIGN.md\n\n${ctx.design.trim()}`);
|
||||
}
|
||||
appendSurfaceBriefContext(parts, ctx);
|
||||
parts.push(buildResolvedContextDirective(ctx, cliOptions, { targetExists }));
|
||||
appendDetectorFallback(parts, ctx);
|
||||
|
||||
@@ -1151,6 +1151,18 @@ describe('context.mjs CLI', () => {
|
||||
assert.doesNotMatch(res.stdout, /WORLD_DISCOVERY_REQUIRED:/);
|
||||
});
|
||||
|
||||
it('prints DESIGN.md even when PRODUCT.md is missing', () => {
|
||||
// The skill resumes after init writes PRODUCT.md without rerunning this
|
||||
// script, so a DESIGN.md withheld from the no-PRODUCT.md branch is never
|
||||
// seen at all. Emit incumbent visual authority on both branches.
|
||||
write('DESIGN.md', '# Acme design\n\nUNIQUE_DESIGN_MARKER\n');
|
||||
const res = spawnSync(process.execPath, [SCRIPT_PATH], { cwd: scratch, encoding: 'utf8', env: { ...process.env, IMPECCABLE_NO_UPDATE_CHECK: '1' } });
|
||||
assert.equal(res.status, 0);
|
||||
assert.match(res.stdout, /^NO_PRODUCT_MD:/);
|
||||
assert.match(res.stdout, /# DESIGN\.md\n\n# Acme design/);
|
||||
assert.match(res.stdout, /UNIQUE_DESIGN_MARKER/);
|
||||
});
|
||||
|
||||
it('concatenates PRODUCT.md and DESIGN.md with a --- separator', async () => {
|
||||
write('PRODUCT.md', '# Acme product\n');
|
||||
write('DESIGN.md', '# Acme design\n');
|
||||
|
||||
Reference in New Issue
Block a user