singularity-forge/docs/specs/sf-prompt-modularization.md
Mikael Hugo a8a28bd7c0 docs(specs): add sf-prompt-modularization.md operator guide
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-15 19:47:20 +02:00

5.4 KiB
Raw Blame History

SF Prompt Modularization

Human-readable contract for the manifest-driven prompt context system.

Status

M004 — Phase 3 complete. All builders migrated to composeUnitContext v2.

Overview

Every autonomous unit type (plan-milestone, execute-task, deploy, …) declares what context it needs in a manifest. The composer reads the manifest and orchestrates artifact resolution, producing the ## Inlined Context block that each prompt template receives.

This replaces the pre-Phase-3 approach where each builder hand-wired file reads and DB queries inline.

Two composer APIs

API Purpose When to use
composeInlinedContext(unitType, resolveArtifact) v1 — resolves artifacts.inline keys only Deprecated. Retained in unit-context-composer.js for external consumers. Do not use in new builders.
composeUnitContext(unitType, opts) v2 — resolves prepend, inline, excerpt, and computed artifacts Use for all new builders. All in-tree builders now call this.

composeUnitContext contract

composeUnitContext(unitType: string, opts: {
  base: string;                          // repo root
  resolveArtifact?: (key: string) => Promise<string | null>;
  resolveExcerpt?: (key: string) => Promise<string | null>;
  computed?: Record<string, { build: (inputs, base) => string | null }>;
}) => Promise<{ prepend: string; inline: string }>
  • prepend — computed blocks that should appear before the main inline content.
  • inline — the joined context block suitable for {{inlinedContext}} substitution.
  • Unknown unitType returns { prepend: "", inline: "" } — callers fall through to default behavior.
  • Missing resolvers or registry entries are skipped silently (no error).

Manifest schema

interface UnitManifest {
  skills: { mode: "all" | "planning" | string[] };
  knowledge: "full" | "scoped" | "critical-only" | "none";
  memory: "prompt-relevant" | "critical-only" | "none";
  codebaseMap: boolean;
  preferences: "active-only" | "none";
  tools: string[];
  prepend?: string[];           // computed artifact ids (e.g. ["overrides"])
  artifacts: {
    inline: string[];           // static artifact keys, resolved in order
    excerpt: string[];          // excerpt artifact keys
    onDemand: string[];         // referenced but not auto-inlined
    computed?: string[];        // async computed artifact ids (e.g. ["knowledge", "graph"])
  };
  maxSystemPromptChars: number;
}

Stable artifact keys (ARTIFACT_KEYS)

Keys are stable identifiers, not paths. The resolver maps a key to its source (file, DB row, computed block).

Milestone-scoped: roadmap, milestone-context, milestone-summary, milestone-validation, milestone-research, milestone-plan

Slice-scoped: slice-context, slice-research, slice-plan, slice-summary, slice-summaries, slice-uat, slice-assessment

Task-scoped: task-plan, task-summary, prior-task-summaries, dependency-summaries, blocker-summaries

Project-scoped: requirements, decisions, project, templates, queue

Validation-scoped: verification-classes, outstanding-items, previous-validation

History-scoped: prior-milestone-summary

Migration decision matrix

Builder complexity Recommendation Example
Simple (13 static artifacts, no knowledge splice) Full v2 via composeUnitContext deploy, release, rollback, challenge
Medium (46 static artifacts, optional knowledge/graph) v2 inline + imperative knowledge splice research-milestone, complete-slice, reassess-roadmap
Complex (many artifacts, computed prepend, conditional logic) v2 with full computed registry plan-milestone, research-slice, plan-slice, replan-slice
Fully imperative (no composer call) Keep imperative; add manifest for documentation execute-task, reactive-execute

Budget and caching

  • resolvePromptBudgets() computes context-window-scaled budgets once per dispatch tick (1-second TTL). Do not add additional caches.
  • capPreamble() caps inlined context at min(30K chars, scaled inline budget).
  • Exceeding maxSystemPromptChars logs a telemetry event; the composer does not truncate.

Verification

  • auto-prompts-phase3.test.mjs — v2 contracts for plan-milestone, replan-slice, validate-milestone, research-slice.
  • auto-prompts-complete-slice.test.mjs — complete-slice closeout contract.
  • auto-prompts-v2-migration.test.mjs — regression guard for all migrated builders (research-milestone, run-uat, deploy, smoke-production, release, rollback, challenge).
  • unit-context-manifest-computed.test.mjs — manifest computed keys match builder behavior.

Adding a new artifact key

  1. Add the key to ARTIFACT_KEYS in unit-context-manifest.js.
  2. Add the key to the inline / excerpt / onDemand / computed list of every manifest that needs it.
  3. Implement the resolver in the builder's resolveArtifact function.
  4. Add a regression test that asserts the artifact appears in the prompt.

Adding a new computed artifact type

  1. Define the builder function (e.g. inlineKnowledgeBudgeted).
  2. Register it in the computed registry passed to composeUnitContext:
    computed: {
      knowledge: { build: (inputs, base) => inlineKnowledgeBudgeted(base, inputs.keywords) }
    }
    
  3. Add the id to manifest.artifacts.computed.
  4. Add a test that asserts the computed block appears in the output.