MCPcopy Create free account
hub / github.com/Facets-cloud/flow / TestHookSessionStartRequiresSkillInvocation

Function TestHookSessionStartRequiresSkillInvocation

internal/app/hook_test.go:74–122  ·  view source on GitHub ↗

TestHookSessionStartRequiresSkillInvocation pins the invariant that the injected additionalContext explicitly instructs the session to invoke the flow skill via the Skill tool as its first action, and mentions the task slug so the agent has something anchor-visible. The hook discovers the bound task

(t *testing.T)

Source from the content-addressed store, hash-verified

72// $CLAUDE_CODE_SESSION_ID (set by Claude Code in every real session)
73// rather than by reading FLOW_TASK.
74func TestHookSessionStartRequiresSkillInvocation(t *testing.T) {
75 setupFlowRoot(t)
76
77 // Seed a task and pin its session_id so the reverse-lookup finds it.
78 seedTask(t, "some-slug")
79 const sid = "deadbeef-1234-4567-8abc-def012345678"
80 db := openFlowDB(t)
81 if _, err := db.Exec(
82 `UPDATE tasks SET session_id=?, status='in-progress', session_started=? WHERE slug='some-slug'`,
83 sid, flowdb.NowISO(),
84 ); err != nil {
85 t.Fatal(err)
86 }
87 t.Setenv("CLAUDE_CODE_SESSION_ID", sid)
88
89 out := captureStdout(t, func() {
90 if rc := cmdHookSessionStart(nil); rc != 0 {
91 t.Fatalf("rc=%d", rc)
92 }
93 })
94
95 var parsed struct {
96 HookSpecificOutput struct {
97 HookEventName string `json:"hookEventName"`
98 AdditionalContext string `json:"additionalContext"`
99 } `json:"hookSpecificOutput"`
100 }
101 if err := json.Unmarshal([]byte(out), &parsed); err != nil {
102 t.Fatalf("parse hook output: %v\nraw: %s", err, out)
103 }
104 if parsed.HookSpecificOutput.HookEventName != "SessionStart" {
105 t.Errorf("hookEventName = %q, want SessionStart", parsed.HookSpecificOutput.HookEventName)
106 }
107 ctx := parsed.HookSpecificOutput.AdditionalContext
108 if !strings.Contains(ctx, "Skill tool") {
109 t.Errorf("additionalContext must instruct Skill tool invocation, got:\n%s", ctx)
110 }
111 if !strings.Contains(ctx, "`flow` skill") {
112 t.Errorf("additionalContext must name the `flow` skill, got:\n%s", ctx)
113 }
114 // Self-registration is gone — the UUID is pre-allocated by `flow do`.
115 // Make sure we don't regress by re-introducing it here.
116 if strings.Contains(ctx, "register-session") {
117 t.Errorf("additionalContext should not mention register-session (pre-allocated by flow do):\n%s", ctx)
118 }
119 if !strings.Contains(ctx, "some-slug") {
120 t.Errorf("additionalContext should mention the task slug, got:\n%s", ctx)
121 }
122}
123
124// TestHookUserPromptSubmitBoundEmitsAnchor pins the bound-session
125// contract: when the current $CLAUDE_CODE_SESSION_ID belongs to a task,

Callers

nothing calls this directly

Calls 6

NowISOFunction · 0.92
setupFlowRootFunction · 0.85
seedTaskFunction · 0.85
openFlowDBFunction · 0.85
captureStdoutFunction · 0.85
cmdHookSessionStartFunction · 0.85

Tested by

no test coverage detected