mirror of
https://github.com/garrytan/gstack.git
synced 2026-06-25 19:20:00 +02:00
feat(preamble): add "Handling 5+ options — split, never drop" rule
Agents repeatedly hit Conductor's 4-option AskUserQuestion cap and silently drop one option to fit, shrinking the user's decision space. This rule names the bug and gives two compliant shapes: batch into ≤4-groups (for coherent alternatives) or split into N sequential per-option calls (for independent scope items, default). Inline preamble subsection is ~15 lines (rule + buckets + pointer). Full reference with worked examples, Hold/dependency semantics, and final-summary validation lives in docs/askuserquestion-split.md. The agent loads the docs file on demand when N>4. Per-option call shape: D<N>.k header, ELI10, Recommendation, kind-note (no completeness score — decision actions, not coverage), Include / Defer / Cut / Hold buckets. Hold stops the chain immediately; the final D<N>.final call validates dependencies and confirms the assembled scope. question_ids: <skill>-split-<option-slug> (kebab-case ASCII, ≤64 chars). Also fixes orphan "12. " prefix on the existing CJK rule. Tier-2+ skills inherit via the existing resolver. SKILL.md regenerated for all 41 affected skills + 3 golden fixtures. Net diff per SKILL.md: ~34 lines (vs ~110 for the full inline version). 6 tests pin the inline contract (4-option cap, buckets, D-numbering, docs pointer, runtime AUTO_DECIDE gate reference, orphan 12 regression). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -119,3 +119,45 @@ describe('generateAskUserFormat — v1.7.0.0 Pros/Cons format', () => {
|
||||
expect(out).toMatch(/Per-skill instructions may add/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('generateAskUserFormat — 5+ option split rule (slim inline + docs pointer)', () => {
|
||||
const out = generateAskUserFormat(makeCtx());
|
||||
|
||||
// 5 highest-signal pins. The full rule lives in
|
||||
// docs/askuserquestion-split.md; this contract only checks what the
|
||||
// inline subsection MUST surface so the agent can act without
|
||||
// reading the docs file for routine 5-option splits.
|
||||
|
||||
test('forbids dropping options to fit the 4-option cap', () => {
|
||||
expect(out).toMatch(/caps every call at \*\*4 options\*\*/);
|
||||
expect(out).toMatch(/NEVER\s+drop, merge, or silently defer/);
|
||||
});
|
||||
|
||||
test('names the Include / Defer / Cut / Hold buckets', () => {
|
||||
expect(out).toMatch(/A\) Include/);
|
||||
expect(out).toMatch(/B\) Defer/);
|
||||
expect(out).toMatch(/C\) Cut/);
|
||||
expect(out).toMatch(/D\) Hold/);
|
||||
});
|
||||
|
||||
test('specifies D<N>.k child numbering and D<N>.final summary', () => {
|
||||
expect(out).toContain('D<N>.k');
|
||||
expect(out).toContain('D<N>.final');
|
||||
});
|
||||
|
||||
test('AUTO_DECIDE is gated at runtime, not just collision-resistance', () => {
|
||||
expect(out).toContain('bin/gstack-question-preference');
|
||||
expect(out).toContain('*-split-*');
|
||||
expect(out).toContain('never AUTO_DECIDE-eligible');
|
||||
});
|
||||
|
||||
test('points to docs/askuserquestion-split.md for the full rule', () => {
|
||||
expect(out).toContain('docs/askuserquestion-split.md');
|
||||
expect(out).toMatch(/Read on demand when N>4/);
|
||||
});
|
||||
|
||||
test('regression: orphan "12." prefix removed from CJK rule', () => {
|
||||
expect(out).not.toContain('12. **Non-ASCII');
|
||||
expect(out).toContain('**Non-ASCII characters');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user