Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions scripts/generate-guidance.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ describe("canonical guidance generation", () => {
}
expect(GUIDANCE_CUES.rebaseCheck).toContain("Active summarized history is present");
expect(GUIDANCE_CUES.rebaseCheck).toContain("structural reset and cold start");
expect(GUIDANCE_CUES.rebaseCheck).toContain("cold-start test passes");
expect(GUIDANCE_CUES.timelineActive).toContain("`active`");
expect(GUIDANCE_CUES.timelineCheckpoints).toContain("`checkpoints`");
expect(GUIDANCE_CUES.timelineSearch).toContain("`search`");
Expand Down
84 changes: 58 additions & 26 deletions skills/context-management/CORE.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion skills/context-management/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: "Resolve advanced ACM cases: ambiguous earliest-safe-base selection

# Advanced Context Management

The always-on **CORE owns the normal path**: ordinary checkpointing, clear phase folds, clear burst folds, pressure checks, task-end handling, and an obvious rebase all stay there. This Skill resolves one advanced condition at a time.
The always-on **CORE owns the normal path**: the working-set invariant, judgment layers, decision smells, recognizable moments, fold and rebase criteria, ordinary checkpointing, clear phase folds, clear burst folds, rebase checks under pressure, task-end handling, and an obvious rebase all stay there. This Skill resolves one advanced condition at a time when CORE's criteria pass but the decision remains ambiguous or a result reports an exceptional outcome.

Select the reference whose observable condition is active:

Expand Down
2 changes: 1 addition & 1 deletion src/checkpoint-tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export function registerCheckpointTool(pi: ExtensionAPI): void {
description: TOOL_DESCRIPTIONS.checkpoint,
promptSnippet: "Label a recoverable session boundary without changing context",
promptGuidelines: [
"Use acm_checkpoint to preflight each distinct user goal before managed work and to label later phase, burst, pause, milestone, or completion boundaries.",
"Use acm_checkpoint to preflight each distinct user goal before managed work makes rewind expensive, and to label later phase, burst, pause, milestone, or completion boundaries.",
],
parameters: schema,
renderShell: "self",
Expand Down
12 changes: 6 additions & 6 deletions src/context-usage-nudge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,17 +154,17 @@ export function buildContextUsageNudgeMessage(nudge: PendingContextUsageNudge):

const guidance = nudge.level === 30
? [
"Continue the current work normally. At the next natural semantic boundary, consider whether current task requirements permit a safe fold or rebase travel.",
"Travel is optional, but keeping the active context small is preferred when it can be done without losing needed working state.",
"Continue the current work normally. At the next natural semantic boundary, check decision smells and whether fold criteria can pass against the working-set invariant.",
"Prefer a smaller active working set when a complete handoff can preserve needed state and make NEXT executable; otherwise keep required detail live.",
]
: nudge.level === 50
? [
"Context pressure is becoming material. Based on the current task requirements, actively look for the next safe opportunity for a fold or rebase travel.",
"Travel is recommended when a complete handoff can preserve the required working state and make NEXT executable. Do not travel if important context is still needed, but prefer returning to a smaller active context when safely possible.",
"Context pressure is becoming material. Raise the priority of a rebase check, and look for the next recognizable moment where fold criteria and cold start can pass.",
"Travel earns its place only when the handoff preserves required working state and makes NEXT executable. Prefer restoring a smaller working set when those criteria hold.",
]
: [
"Context pressure is high. At the earliest safe semantic boundary, strongly consider a fold or rebase travel if current task requirements allow a complete and recoverable handoff.",
"Keeping the active context small is strongly preferred, but correctness, task continuity, and recoverability take priority. If no safe travel is available, continue normally; native compaction is acceptable for a genuinely long task.",
"Context pressure is high. At the earliest safe semantic boundary, prefer a fold or rebase when fold criteria and cold start pass.",
"Correctness, task continuity, recoverability, and cold start outrank pressure. If no safe transition is available, continue with required detail live; native compaction is acceptable for a genuinely long task.",
];

return {
Expand Down
20 changes: 10 additions & 10 deletions src/generated-guidance.ts

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/travel-tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ export function registerTravelTool(pi: ExtensionAPI, runtime: AcmSessionRuntime)
description: TOOL_DESCRIPTIONS.travel,
promptSnippet: "Fold a named boundary or rebase summaries into a recoverable handoff",
promptGuidelines: [
"Use acm_travel only when the boundary is named, NEXT is executable from the handoff, and omitted raw history remains recoverable through a direct pointer.",
"Call acm_travel alone in its assistant tool batch; never combine this context mutation with sibling tool calls.",
"Use acm_travel when fold criteria hold: the boundary is named, NEXT is executable from the handoff, and omitted raw history remains recoverable through a direct pointer.",
"Call acm_travel alone in its assistant tool batch; mixed batches are rejected before mutation.",
],
parameters: schema,
executionMode: "sequential",
Expand Down
9 changes: 6 additions & 3 deletions test/context-nudge.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ describe("ACM context usage reminders", () => {
});
expect(fixture.sentMessages[0]?.message.content).toContain("[ACM Context Reminder · 30% tier]");
expect(fixture.sentMessages[0]?.message.content).toContain("next natural semantic boundary");
expect(fixture.sentMessages[0]?.message.content).toContain("Travel is optional");
expect(fixture.sentMessages[0]?.message.content).toContain("decision smells");
expect(fixture.sentMessages[0]?.message.content).toContain("fold criteria");
expect(fixture.sentMessages[0]?.message.content).toContain("working-set invariant");

fixture.setUsagePercent(35);
await fixture.emit("context", { messages: [] });
Expand Down Expand Up @@ -248,8 +250,9 @@ describe("ACM context usage reminders", () => {
},
options: { deliverAs: "followUp" },
});
expect(fixture.sentMessages[0]?.message.content).toContain("actively look for the next safe opportunity");
expect(fixture.sentMessages[0]?.message.content).toContain("Travel is recommended");
expect(fixture.sentMessages[0]?.message.content).toContain("Raise the priority of a rebase check");
expect(fixture.sentMessages[0]?.message.content).toContain("Travel earns its place only when");
expect(fixture.sentMessages[0]?.message.content).toContain("recognizable moment");
});

test("a successful travel starts a new baseline-only reminder cycle", async () => {
Expand Down
104 changes: 49 additions & 55 deletions test/guidance-quality.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,79 +4,73 @@ import { ACM_CORE, GUIDANCE_CUES, TOOL_DESCRIPTIONS } from "../src/generated-gui
const skillFile = (path: string) => Bun.file(new URL(`../skills/context-management/${path}`, import.meta.url)).text();

describe("ACM guidance quality", () => {
test("preserves the base workflow while bounding semantic rebase", () => {
for (const baseBehavior of [
test("unifies judgment layers on the working-set invariant", () => {
for (const situation of [
"Phase, attempt, or batch item starts",
"Unbounded burst or risky step is next",
"Findings are distilled",
"Direction is rejected or superseded",
"Final answer is next",
]) {
expect(ACM_CORE).toContain(baseBehavior);
expect(ACM_CORE).toContain(situation);
}
expect(ACM_CORE).toContain("Local fold example");
expect(ACM_CORE).toContain("Finished-chain rebase example");
expect(ACM_CORE).not.toContain("Failed-direction example");
expect(ACM_CORE).toContain("Structural reset passes only when");
expect(ACM_CORE).toContain("projected summary depth does not grow");
expect(ACM_CORE).toContain("Cold start passes only when");
expect(ACM_CORE.length).toBeLessThan(7500);
expect(GUIDANCE_CUES.rebaseCheck).toContain("Active summarized history is present");
expect(ACM_CORE).toContain("Call `acm_travel` alone in its assistant tool batch");
expect(TOOL_DESCRIPTIONS.travel).toContain("must run alone in its assistant tool batch");
expect(ACM_CORE).toContain("Process detail accumulates naturally");
expect(ACM_CORE).toContain("keep live what NEXT needs");
expect(ACM_CORE).toContain("### Working-set invariant");
expect(ACM_CORE).toContain("### How judgment layers fit together");
expect(ACM_CORE).toContain("**Decision smells** prompt a pause");
expect(ACM_CORE).toContain("**Recognizable moments** map a situation");
expect(ACM_CORE).toContain("**Failure shapes** describe what went wrong");
expect(ACM_CORE).toContain("### Decision smells");
expect(ACM_CORE).toContain("### Recognizable moments");
expect(ACM_CORE).toContain("lightest transition that does");
expect(ACM_CORE).not.toContain("| Event | Required transition |");
expect(ACM_CORE).not.toContain("| Situation | Judgment |");
expect(ACM_CORE).toContain("### Fold criteria");
expect(ACM_CORE).toContain("### Rebase criteria");
expect(ACM_CORE).toContain("### Failure shapes");
expect(ACM_CORE).toContain("Before `acm_travel`, answer in one line");
expect(ACM_CORE).toContain("Cold start remains hard");
expect(ACM_CORE).toContain("not answers by proximity or anchor gravity");
expect(ACM_CORE).toContain("Why: findings are distilled");
expect(ACM_CORE).not.toContain("**NEXT stalls**");
expect(ACM_CORE).toContain("Ambiguous base selection, interleaved fronts, or raw-node fallback");
expect(ACM_CORE).toContain("load the context-management skill");
expect(ACM_CORE).toContain("managed-chain workflow");
expect(ACM_CORE).toContain("without rereading archived summaries");
expect(GUIDANCE_CUES.rebaseCheck).toContain("cold-start test passes");
expect(TOOL_DESCRIPTIONS.travel).toContain("Mixed tool batches are rejected");
});

test("front-loads a checkable checkpoint preflight", () => {
test("front-loads recoverability preflight as a cost judgment", () => {
const invariantIndex = ACM_CORE.indexOf("### Working-set invariant");
const layersIndex = ACM_CORE.indexOf("### How judgment layers fit together");
const preflightIndex = ACM_CORE.indexOf("### ACM preflight");
const vocabularyIndex = ACM_CORE.indexOf("### Vocabulary");

expect(preflightIndex).toBeGreaterThan(-1);
expect(preflightIndex).toBeLessThan(vocabularyIndex);
expect(ACM_CORE).toContain("A distinct user goal begins with an **ACM preflight** on the branch that will carry it");
expect(ACM_CORE).toContain("First complete any required `New request arrives over finished work` transition");
expect(ACM_CORE).toContain("then call `acm_checkpoint` with a semantic `<chain>-start` name before managed work");
expect(ACM_CORE).toContain("When no finished-chain transition is required, the checkpoint call is the first action");
expect(ACM_CORE).toContain("Managed work includes investigation, planning, delegation, any non-ACM tool call");
expect(ACM_CORE).toContain("the checkpoint was created or reused");
expect(ACM_CORE).toContain("follow the recovery guidance in its result before proceeding");
expect(ACM_CORE).toContain("A text-only direct reply requiring no managed work stays outside");
expect(ACM_CORE).toContain("live detail the next action will reason over");
expect(ACM_CORE).toContain("Name the boundary before choosing a target");
expect(ACM_CORE).toContain("without archived summaries");
expect(ACM_CORE).toContain("checkpoint its `-start` boundary before acting");
expect(ACM_CORE).toContain("checkpoint before output or side effects arrive");
expect(ACM_CORE).not.toContain("| New chain starts |");
expect(TOOL_DESCRIPTIONS.checkpoint.startsWith("Preflight a distinct user goal")).toBe(true);
expect(TOOL_DESCRIPTIONS.checkpoint.length).toBeLessThan(800);
expect(invariantIndex).toBeGreaterThan(-1);
expect(invariantIndex).toBeLessThan(layersIndex);
expect(layersIndex).toBeLessThan(vocabularyIndex);
expect(preflightIndex).toBeGreaterThan(vocabularyIndex);
expect(ACM_CORE).toContain("against this invariant");
expect(ACM_CORE).toContain("Recoverability has a cost curve");
expect(ACM_CORE).toContain("opening a **managed chain**");
expect(ACM_CORE).not.toContain("the checkpoint call is the first action");
expect(TOOL_DESCRIPTIONS.checkpoint).toContain("before managed work makes rewind expensive");
});

test("routes one advanced condition at a time and reroutes on state change", async () => {
const skill = await skillFile("SKILL.md");
expect(skill).toContain("CORE owns the normal path");
expect(skill).toContain("ordinary checkpointing");
expect(skill).toContain("clear phase folds");
expect(skill).toContain("clear burst folds");
expect(skill).toContain("task-end handling");
expect(skill).toContain("working-set invariant");
expect(skill).toContain("decision smells");
expect(skill).toContain("judgment layers");
expect(skill).toContain("Load one reference at a time");
expect(skill).toContain("observable condition changes");
expect(skill).toContain("replace the active reference");
});

test("keeps target and recovery criteria factual and checkable", async () => {
const target = await skillFile("references/target-selection.md");
const archive = await skillFile("references/archive-recovery.md");
const exceptional = await skillFile("references/exceptional-recovery.md");

expect(target).toContain("tree topology orders them");
expect(target).toContain("must precede at least one active `branch_summary`");
expect(target).toContain("projected summary depth must not grow");
expect(target).toContain("every surviving item has one authoritative home");
expect(archive).toContain("Pending is scheduled work, not success");
expect(archive).toContain("return to the Skill router and replace this reference");
expect(archive).not.toContain("structural effect");
expect(exceptional).toContain("Backup rollback failure");
expect(exceptional).toContain("branch creation was not applied");
expect(exceptional).toContain("Indeterminate branch mutation");
expect(exceptional).toContain("mutation may have landed");
test("re-anchors tool cues with observables and positive targets", () => {
expect(GUIDANCE_CUES.checkpointStart).toContain("Recoverability confirmed");
expect(GUIDANCE_CUES.travelTask).toContain("handoff working set");
expect(GUIDANCE_CUES.travelTask).not.toContain("do not reintroduce");
expect(GUIDANCE_CUES.checkpointDone).toContain("working-set invariant");
});
});
1 change: 1 addition & 0 deletions test/tool-descriptions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ describe("ACM tool description contract", () => {
expect(timelineTool).toContain("description: TOOL_DESCRIPTIONS.timeline");
expect(travelTool).toContain("description: TOOL_DESCRIPTIONS.travel");
expect(generatedGuidance).toContain("Preflight a distinct user goal on the branch that will carry it");
expect(generatedGuidance).toContain("before managed work makes rewind expensive");
expect(generatedGuidance).toContain("Names are unique across the session tree and case-sensitive");
expect(generatedGuidance).toContain("Omitting target labels the nearest meaningful USER/AI turn");
expect(generatedGuidance).toContain("without branching or folding the active context");
Expand Down