diff --git a/.pi/skills/problem-breakdown/SKILL.md b/.pi/skills/problem-breakdown/SKILL.md index 9773767..a21218a 100644 --- a/.pi/skills/problem-breakdown/SKILL.md +++ b/.pi/skills/problem-breakdown/SKILL.md @@ -74,15 +74,15 @@ After a user-story-conversation produces an Allium spec and fast-check propertie For each rule/invariant from the spec, decide whether to write a **property-based test** or an **example-based test**. Discuss with the user: -| Signal | Choose | Rationale | -| --------------------------------------------------- | --------------- | -------------------------------------------- | -| `fc.property` would be trivially short (< 5 lines) | Example-based | Property overhead not worth it | -| Invariant is a simple arithmetic relationship | Example-based | One or two examples cover all cases | -| State transition has a small, finite input space | Example-based | Exhaustive examples are feasible | -| Invariant involves collections, sequences, or math | Property-based | Need random inputs to find edge cases | -| Rule has complex guards (requires + ensures chains) | Property-based | Random inputs surface hidden preconditions | -| User says "just show it works" | Example-based | Confidence test, not a robustness guarantee | -| User says "prove it always holds" | Property-based | That's what properties are for | +| Signal | Choose | Rationale | +| --------------------------------------------------- | -------------- | ------------------------------------------- | +| `fc.property` would be trivially short (< 5 lines) | Example-based | Property overhead not worth it | +| Invariant is a simple arithmetic relationship | Example-based | One or two examples cover all cases | +| State transition has a small, finite input space | Example-based | Exhaustive examples are feasible | +| Invariant involves collections, sequences, or math | Property-based | Need random inputs to find edge cases | +| Rule has complex guards (requires + ensures chains) | Property-based | Random inputs surface hidden preconditions | +| User says "just show it works" | Example-based | Confidence test, not a robustness guarantee | +| User says "prove it always holds" | Property-based | That's what properties are for | **Default:** start with example-based tests. Escalate to property-based only when the user or the spec demands broader coverage. This keeps the yak list smaller and faster to execute. @@ -167,13 +167,13 @@ Clear description of the change. ## Integration with Other Skills -| Skill | When to run problem-breakdown after | -| ---------------------- | ------------------------------------------------ | -| user-story-conversation| After Allium spec + properties are produced | -| distill | After spec extraction, before test generation | -| tend | After spec changes, to plan implementation updates | -| propagate | When propagate produces obligations, to break them into file-level steps | -| weed | After divergence is found, to plan alignment fixes | +| Skill | When to run problem-breakdown after | +| ----------------------- | ------------------------------------------------------------------------ | +| user-story-conversation | After Allium spec + properties are produced | +| distill | After spec extraction, before test generation | +| tend | After spec changes, to plan implementation updates | +| propagate | When propagate produces obligations, to break them into file-level steps | +| weed | After divergence is found, to plan alignment fixes | ## Example: Full Breakdown diff --git a/src/Character.ts b/src/Character.ts index f6624f0..054dcb8 100644 --- a/src/Character.ts +++ b/src/Character.ts @@ -10,8 +10,8 @@ import type { Status } from './Status.ts'; import { StatusAlive, StatusDead } from './Status.ts'; import type { CharacterState } from './CharacterState.ts'; import type { Faction } from './Faction.ts'; -import type { MagicalWeapon } from './MagicalWeapon.ts'; -import type { HealingObject } from './HealingObject.ts'; +import type { DamageDealer } from './magical-objects/magical-object-types.ts'; +import type { Healer } from './magical-objects/magical-object-types.ts'; export interface CharacterCtor { name: string; @@ -233,10 +233,7 @@ export class Character { * Dead characters cannot use weapons. Only the owner can use a weapon. * Returns updated weapon and target. */ - useWeapon( - weapon: MagicalWeapon, - target: Character, - ): { weapon: MagicalWeapon; target: Character } { + useWeapon(weapon: DamageDealer, target: Character): { weapon: DamageDealer; target: Character } { // Dead characters cannot use weapons if (this.status.kind === 'dead') return { weapon, target }; // Only the owner can use the weapon @@ -249,10 +246,7 @@ export class Character { * Dead characters cannot use healing objects. * Returns updated object and character. */ - useHealingObject( - object: HealingObject, - amount: number, - ): { object: HealingObject; character: Character } { + useHealingObject(object: Healer, amount: number): { object: Healer; character: Character } { // Dead characters cannot use healing objects if (this.status.kind === 'dead') return { object, character: this }; return object.heal(this, amount); diff --git a/src/HealingObject.ts b/src/HealingObject.ts index c202bd5..9ce47e9 100644 --- a/src/HealingObject.ts +++ b/src/HealingObject.ts @@ -9,8 +9,9 @@ import { Character } from './Character.ts'; import { Level } from './Level.ts'; import { MagicalObject } from './MagicalObject.ts'; +import type { Healer } from './magical-objects/magical-object-types.ts'; -export class HealingObject extends MagicalObject { +export class HealingObject extends MagicalObject implements Healer { private constructor( health: number, maxHealth: number, diff --git a/src/MagicalWeapon.ts b/src/MagicalWeapon.ts index e9e210c..db87244 100644 --- a/src/MagicalWeapon.ts +++ b/src/MagicalWeapon.ts @@ -7,8 +7,9 @@ */ import { Character } from './Character.ts'; import { MagicalObject } from './MagicalObject.ts'; +import type { DamageDealer } from './magical-objects/magical-object-types.ts'; -export class MagicalWeapon extends MagicalObject { +export class MagicalWeapon extends MagicalObject implements DamageDealer { readonly #damage: number; readonly #owner: Character; diff --git a/src/magical-objects/magical-object-types.ts b/src/magical-objects/magical-object-types.ts new file mode 100644 index 0000000..e41e01f --- /dev/null +++ b/src/magical-objects/magical-object-types.ts @@ -0,0 +1,24 @@ +/** + * Magical object type interfaces — break the circular dependency between + * Character.ts and the magical object implementations. + * + * These interfaces describe magical objects from Character's point of view, + * so Character can depend on abstractions rather than concrete classes. + */ +import type { Character } from '../Character.ts'; +import type { MagicalObjectStatus } from '../MagicalObject.ts'; + +/** A magical object that deals damage — from Character's point of view */ +export interface DamageDealer { + readonly owner: Character; + readonly health: number; + readonly status: MagicalObjectStatus; + use(target: Character): { weapon: DamageDealer; target: Character }; +} + +/** A magical object that heals — from Character's point of view */ +export interface Healer { + readonly health: number; + readonly status: MagicalObjectStatus; + heal(character: Character, amount: number): { object: Healer; character: Character }; +} diff --git a/transcripts/break-down-horizontal-refactoring-into-yaks.html b/transcripts/break-down-horizontal-refactoring-into-yaks.html new file mode 100644 index 0000000..ec228ff --- /dev/null +++ b/transcripts/break-down-horizontal-refactoring-into-yaks.html @@ -0,0 +1,13112 @@ + + + + + + Session Export + + + + + +
+ + +
+
+
+
+
+ +
+
+ + + + + + + + + + + + + diff --git a/transcripts/create-task-breakdown-with-yaks-skill.html b/transcripts/create-task-breakdown-with-yaks-skill.html new file mode 100644 index 0000000..60f42b2 --- /dev/null +++ b/transcripts/create-task-breakdown-with-yaks-skill.html @@ -0,0 +1,13112 @@ + + + + + + Session Export + + + + + +
+ + +
+
+
+
+
+ +
+
+ + + + + + + + + + + + +