fix(expand,setup): append behavioral findings to sections 02-behavioral-profile.md actually has (#520)

Both commands told the model to add to "Strongest Behavioral Traits" and
"How I Work Best" / "How [Candidate] Works Best" while also saying "match
existing structure", but the shipped file's headings are "Strongest
Behaviors" and "How You Work Best", so an inferred trait either opened a
duplicate near-identical section or was dropped.

The companion to #519, which fixed the same drift in /reset's skeleton.
Both bullets now name the shipped headings, and a derived test in each
command's suite reads the quoted section names and requires each to be a
## heading of the shipped file; both fail on master.
This commit is contained in:
Ayobami Adegoke authored and GitHub committed 2026-10-08 21:18:08 +02:00
1 parent 895c02191d
commit 760bbc34cf
5 files changed
+65 -2

No files matched your search

+1 -1
View File
@@ -189,7 +189,7 @@ Apply only the confirmed items. Use the Edit tool to add to the relevant section
For each addition, add a brief source annotation in a comment or parenthetical: *(Coursera — Deep Learning Specialisation)*, *(GitHub — project-name)*, etc. This makes future `/expand` runs idempotent.
### Additions to `02-behavioral-profile.md`
- Soft/behavioral signals → append to the "Strongest Behavioral Traits" or "How I Work Best" section (match existing structure)
- Soft/behavioral signals → append to the "Strongest Behaviors" or "How You Work Best" section (the shipped file's `##` headings - match existing structure)
- Always label inferred behavioral additions: *[Inferred from reference letter — Name / review before relying on this]*
---
+1 -1
View File
@@ -167,7 +167,7 @@ For each skill file, compare extracted document content against the current file
**Inference rules** (apply when populating from inferred sources):
- **`01-candidate-profile.md` (`## Independent Projects`):** Source is `projects/` documents. Extract structured project entries formatted as `- **[PROJECT_NAME]**: [DESCRIPTION with tech stack and measurable outcome]`. Ground all claims in the document text.
- **`02-behavioral-profile.md`:** Source is LinkedIn About + recommendation letters. Extract recurring themes, adjectives, phrases about how the candidate works. Add only to "Strongest Behavioral Traits", "How [Candidate] Works Best", or "Management Style Preferences" sections. Do not overwrite existing scored assessments. Always label inferred additions: *[Inferred from LinkedIn About / Reference letter - review before relying on this]*
- **`02-behavioral-profile.md`:** Source is LinkedIn About + recommendation letters. Extract recurring themes, adjectives, phrases about how the candidate works. Add only to the "Strongest Behaviors", "How You Work Best", or "Management Style Preferences" sections (the shipped file's `##` headings). Do not overwrite existing scored assessments. Always label inferred additions: *[Inferred from LinkedIn About / Reference letter - review before relying on this]*
- **`03-writing-style.md`:** Source is `cover_letter.tex` files. Extract recurring patterns. Add as observations under "## Patterns Observed in Past Applications". Do not modify existing rules. Only add if 2+ cover letters show a genuine pattern.
- **`04-job-evaluation.md`:** Source is `job_posting.md` + `outcome.md` pairs. If an application reached interview or offer: note role type and sector as a confirmed strong-fit signal. If 2+ applications repeat a no-response or rejection pattern: note it. Add findings under "## Calibration from Past Applications". Do not modify the existing scoring framework.
- **`05-cv-templates.md`:** Source is `cv_draft.tex` files. Extract any profile statement that does not already appear in templates. Label with: *[Used for: <company>_<role>]*. **Ground before extracting:** archived drafts are tailored outputs, not source documents - verify every factual claim in an extracted statement (titles, employers, metrics, technologies) against `01-candidate-profile.md` and drop or correct any claim the profile does not support, keeping only the framing. A tailored draft that drifted must never become a template future applications start from.
+11
View File
@@ -15,6 +15,17 @@ per-file diff commands.
### Fixed
- **`/expand` and `/setup` now append behavioral findings to sections `02-behavioral-profile.md`
actually has** (`.claude/commands/expand.md` Step 5, `.claude/commands/setup.md` Step A7,
`tests/test_expand_command.py`, `tests/test_setup_command.py`) - both told the model to add
to "Strongest Behavioral Traits" and "How I Work Best" / "How [Candidate] Works Best" while
also saying "match existing structure", but the shipped file's headings are "Strongest
Behaviors" and "How You Work Best", so an inferred trait either opened a duplicate
near-identical section or was dropped. The companion to #519, which fixed the same drift in
`/reset`'s skeleton; the maintainer asked for this half as its own PR. Both bullets now name
the shipped headings, and a derived test in each command's suite reads the quoted section
names and requires each to be a `##` heading of the shipped file; both fail on master.
- **`jobnet-search` and `jobdanmark-search` search results now carry the contract's `id`
field** (`search.ts` and `search-normalization.test.ts` in both CLIs, both `SKILL.md`s) -
`/add-portal`'s contract says every search result has at least `id`, `title`, `company`,
+22
View File
@@ -1,10 +1,12 @@
"""Tests for the /expand command specification."""
import re
import unittest
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent.parent
EXPAND_COMMAND_FILE = REPO_ROOT / ".claude" / "commands" / "expand.md"
BEHAVIORAL_PROFILE = REPO_ROOT / ".claude" / "skills" / "job-application-assistant" / "02-behavioral-profile.md"
class ExpandCommandTests(unittest.TestCase):
@@ -39,6 +41,26 @@ class ExpandCommandTests(unittest.TestCase):
self.assertIn("Portfolio & projects grounded in code", text)
self.assertNotIn("documents/projects/", text)
def test_behavioral_additions_name_sections_the_shipped_file_has(self):
# Step 5 told the model to append to "Strongest Behavioral Traits" or
# "How I Work Best" and to "match existing structure" - but the shipped
# 02-behavioral-profile.md has neither heading (it has "Strongest
# Behaviors" and "How You Work Best"), so the addition either landed
# in a duplicate near-identical section or was dropped. Derived from
# the shipped file so a renamed heading fails here until /expand follows.
text = EXPAND_COMMAND_FILE.read_text(encoding="utf-8")
start = text.index("### Additions to `02-behavioral-profile.md`")
section = text[start: text.index("---", start)]
quoted = re.findall(r'"([^"]+)"', section)
self.assertTrue(quoted, "the 02-behavioral-profile step must name its target sections")
headings = {
line[3:].strip() for line in BEHAVIORAL_PROFILE.read_text(encoding="utf-8").splitlines()
if line.startswith("## ")
}
for name in quoted:
with self.subTest(section=name):
self.assertIn(name, headings, f"02-behavioral-profile.md has no '## {name}' heading")
def test_expand_enforces_additive_and_confirmation_principles(self):
text = EXPAND_COMMAND_FILE.read_text(encoding="utf-8")
self.assertIn("Additive only", text)
+30
View File
@@ -10,6 +10,7 @@ on the drafter noticing. A real user (#420) ran `/setup` and then hand-edited bo
files to close the gap.
"""
import os
import re
import unittest
from pathlib import Path
@@ -90,6 +91,35 @@ class TemplatesStillCarryThePlaceholders(unittest.TestCase):
self.assertIn("\\signature{[YOUR_NAME]}", text)
class SetupPathAWritesIntoSectionsTheShippedFilesHave(unittest.TestCase):
"""Step A7 named 02-behavioral-profile.md sections that do not exist.
"Strongest Behavioral Traits" and "How [Candidate] Works Best" are not
headings in the shipped file ("Strongest Behaviors", "How You Work Best"
are), so the "add only to these sections" rule pointed at nothing. The
section names are read from the bullet and checked against the file's
`##` headings, with the placeholder-free spelling required: a reader
cannot match "[Candidate]" against a heading.
"""
def test_behavioral_profile_bullet_names_real_headings(self):
text = COMMAND.read_text(encoding="utf-8")
bullet = next(
line for line in text.splitlines()
if line.startswith("- **`02-behavioral-profile.md`:**")
)
quoted = re.findall(r'"([^"]+)"', bullet)
self.assertTrue(quoted, "the 02-behavioral-profile bullet must name its target sections")
headings = {
line[3:].strip()
for line in (SKILL_DIR / "02-behavioral-profile.md").read_text(encoding="utf-8").splitlines()
if line.startswith("## ")
}
for name in quoted:
with self.subTest(section=name):
self.assertIn(name, headings, f"02-behavioral-profile.md has no '## {name}' heading")
class SetupPathAProjectsIngestion(unittest.TestCase):
"""Guards for /setup Path A document ingestion of documents/projects/."""