Skip to content

WorkCompletionLearning: no learning file is produced (two blockers remain after #972) — plus a design question about the Insights section #1688

Description

@jlacour-git

Following up on #972, which was closed 2026-07-07 with the note that "the hook now reads the work.json registry, so the WORK→LEARNING bridge actually runs".

The two reported bugs are indeed fixed in the current code. The hook still never writes a file, for two different reasons — and I think the second one raises a design question worth asking before anyone fixes the first.

Tested on 7.1.1. hooks/WorkCompletionLearning.hook.ts and hooks/lib/isa-utils.ts are byte-identical to the files in this repo at HEAD.

It has never produced a file

The hook's output filename is ${date}_${time}_work_${slug}.md (writeLearning()). I searched a MEMORY/LEARNING/ corpus of 1077 files accumulated over five months of daily use on 4.0.3, plus the current 7.1.1 tree:

Zero files matching *_work_*.md in either. Every file in that corpus came from the rating/sentiment capture hook, which uses a different name pattern. The folder looks healthy, which is likely why this has stayed invisible across #648, #668 and #972.

Blocker 1 — the ending session is never found

main() resolves the session via findActiveSessionByUUID(sessionId). That helper skips any row whose phase is not in ACTIVE_LOOKUP_PHASES (hooks/lib/isa-utils.ts:541), which deliberately excludes native.

Every session is registered as a native-<uuid> placeholder row at start. The row is only re-bound to a real ISA slug when ISASync.hook.ts fires — a PostToolUse hook on Write/Edit. So:

  • A session that works on an ISA but appends to it via a shell redirect never re-binds.
  • An ISA stays bound to the UUID of the session that first synced it, so a later session working the same ISA is invisible at its own SessionEnd.

Observed: EventLogger kept attributing tool activity to the correct ISA slug for hours while the row still carried a two-day-old session UUID.

$ echo '{"session_id":"<current-session>"}' | bun hooks/WorkCompletionLearning.hook.ts
[WorkCompletionLearning] No active work session for sessionId=<current-session>

Blocker 2 — a resolved row is still classified trivial

With a row that does resolve, the significance gate is:

const filesChangedCount = workMeta.lineage?.files_changed?.length || 0;
const hasSignificantWork = filesChangedCount > 0 || workMeta.source === 'MANUAL';

lineage and source are META.yaml-era fields. ISA frontmatter carries slug, phase, progress, iteration, frozen, created, resumed_at — neither field exists, so filesChangedCount is always 0 and source is always undefined.

$ echo '{"session_id":"<uuid-of-a-real-ISA-row>"}' | bun hooks/WorkCompletionLearning.hook.ts
[WorkCompletionLearning] Trivial work session, skipping learning capture

That row was a multi-day project with 26 criteria and dozens of changed files.

The two blockers are independent — fixing either alone changes nothing.

The design question

This is asked genuinely, not rhetorically: what is meant to fill the Insights section?

With both blockers fixed, a produced file would read:

## What Was Done
- **Files Changed:** 0
- **Tools Used:** None tracked
- **Agents Spawned:** 0

## Insights
*This work session completed successfully. Consider what made it effective:*
- Was the approach straightforward or did it require iteration?
- Were there any blockers or surprises?
- What patterns from this work apply to future tasks?

The three counters are the fields from Blocker 2, so they would stay at zero unless something starts populating them. And the section named Insights contains three fixed questions, identical in every file that would ever be written.

If a later pass is meant to answer them, I could not find what triggers it. If the answers are meant to be model-written, a SessionEnd shell hook may be the wrong place for it, since it has no model to ask — which would make the empty middle a structural property rather than an omission.

I ask because the fix effort depends entirely on the answer:

  • If the intent is a work log, then the metadata header is the product, and the Insights block is arguably better removed than filled. Also worth noting it overlaps with what the session-summary path already writes.
  • If the intent is a learning, the hook needs a producer for the insight, and the two blockers are the smaller half of the problem.

Happy to open a PR for either shape once the intent is clear. Fixing the two blockers alone is straightforward, but it would start emitting files whose most prominent section is empty by construction, so it seemed worth asking first.

Environment

  • LifeOS 7.1.1, Claude Code, macOS
  • hooks/WorkCompletionLearning.hook.ts v1.5.12, unmodified
  • hooks/lib/isa-utils.ts, unmodified

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions