mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-11-02 13:12:50 +00:00
fix(reset): target the headings the shipped skill files actually have (#519)
* fix(reset): target the headings the shipped skill files actually have
Two of /reset profile's Step 3 targets had drifted from the files they
rewrite.
The 05-cv-templates.md step anchored on a section beginning
"**Profile statement templates", a line the guide has never contained
(its heading is "**Create 2-3 profile statement templates for your main
role types:**"), so the wipe found nothing: the user's role-tailored
profile statements, and any *[Used for: ...]* statements /setup Path A
extracted from archived applications, survived a reset that reported
success.
The 02-behavioral-profile.md skeleton used headings the shipped file
does not have ("Strongest Behavioral Traits", "How I Work Best", a
truncated "Growth Areas") and dropped "## Core Behavioral Drives" - the
assessment table /setup collects and /interview reads - so one reset
left the file's headings permanently different from every other fork's.
Anchor on the real heading and re-emit it in the replacement; carry the
shipped headings in order in the skeleton. 01-candidate-profile.md and
07-interview-prep.md were already correct. Two new tests derive both
checks from the shipped files, so a renamed heading fails until /reset
follows it; both fail on master.
* test(reset): place the heading guards above the __main__ guard so a direct run sees them
python tests/test_reset_command.py ran only the five old tests; unittest
discover imports the module and saw all seven, which is why CI was green.
Also drop the CHANGELOG's claim that /setup and /interview name the Core
Behavioral Drives table - neither does.
This commit is contained in:
1 parent
8dbc941642
commit
a011214d60
3 files changed
+102
-6
No files matched your search
@@ -171,11 +171,13 @@ Wait for the user's response.
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
## Strongest Behavioral Traits
|
## Core Behavioral Drives
|
||||||
|
|
||||||
## How I Work Best
|
## Strongest Behaviors
|
||||||
|
|
||||||
## Growth Areas
|
## How You Work Best
|
||||||
|
|
||||||
|
## Growth Areas (frame positively in applications)
|
||||||
|
|
||||||
## Mapping to Job Posting Language
|
## Mapping to Job Posting Language
|
||||||
|
|
||||||
@@ -205,12 +207,12 @@ Also remove any `## Calibration from Past Applications` section, which `/setup`
|
|||||||
|
|
||||||
Leave the rest of `04-job-evaluation.md` intact: the five scoring dimensions and their score bands, the weighting, the Language Gate, the red-flag guidance, the Company Research Checklist and cache schema, and the salary benchmark section. If `/setup` Step 3.4 ever personalizes a value not in the table above, add it here too.
|
Leave the rest of `04-job-evaluation.md` intact: the five scoring dimensions and their score bands, the weighting, the Language Gate, the red-flag guidance, the Company Research Checklist and cache schema, and the salary benchmark section. If `/setup` Step 3.4 ever personalizes a value not in the table above, add it here too.
|
||||||
|
|
||||||
**For `05-cv-templates.md`**, locate the section that begins with `**Profile statement templates` and extends through the role-specific template blocks. Replace only that section with:
|
**For `05-cv-templates.md`**, locate the section that begins with the line `**Create 2-3 profile statement templates for your main role types:**` and extends through the role-specific template blocks, including any statements labeled *[Used for: <company>_<role>]* that `/setup` Path A extracted from archived applications. Stop before the paragraph that begins "Statements labeled" - that is framework guidance, not candidate data. Replace only that section with:
|
||||||
|
|
||||||
```markdown
|
```markdown
|
||||||
**Profile statement templates:**
|
**Create 2-3 profile statement templates for your main role types:**
|
||||||
|
|
||||||
<!-- Run /setup to populate role-specific profile statements -->
|
<!-- SETUP: These are populated based on your background -->
|
||||||
```
|
```
|
||||||
|
|
||||||
Then restore the contact block inside the file's LaTeX template to its placeholder tokens: `\name{[FIRST_NAME]}{[LAST_NAME]}`, `\address{[YOUR_ADDRESS]}{}{}`, `\phone[mobile]{[YOUR_PHONE]}`, `\email{[YOUR_EMAIL]}`, the `\extrainfo{...}` line's `[YOUR_LINKEDIN_URL]` and `[YOUR_GITHUB_URL]`, and `[YOUR_NAME]` in the `pdftitle`. Leave all other content in `05-cv-templates.md` intact.
|
Then restore the contact block inside the file's LaTeX template to its placeholder tokens: `\name{[FIRST_NAME]}{[LAST_NAME]}`, `\address{[YOUR_ADDRESS]}{}{}`, `\phone[mobile]{[YOUR_PHONE]}`, `\email{[YOUR_EMAIL]}`, the `\extrainfo{...}` line's `[YOUR_LINKEDIN_URL]` and `[YOUR_GITHUB_URL]`, and `[YOUR_NAME]` in the `pdftitle`. Leave all other content in `05-cv-templates.md` intact.
|
||||||
|
|||||||
@@ -15,6 +15,23 @@ per-file diff commands.
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- **`/reset profile` now targets the headings the shipped skill files actually have**
|
||||||
|
(`.claude/commands/reset.md` Step 3, `tests/test_reset_command.py`) - two of its Step 3
|
||||||
|
targets had drifted. The `05-cv-templates.md` step anchored on a section beginning
|
||||||
|
`**Profile statement templates`, a line the guide has never contained (its heading is
|
||||||
|
`**Create 2-3 profile statement templates for your main role types:**`), so the wipe found
|
||||||
|
nothing: the user's role-tailored profile statements, and any `*[Used for: ...]*`
|
||||||
|
statements `/setup` Path A extracted from archived applications, survived a reset that
|
||||||
|
reported success. The `02-behavioral-profile.md` skeleton used headings the shipped file
|
||||||
|
does not have (`Strongest Behavioral Traits`, `How I Work Best`, a truncated `Growth Areas`)
|
||||||
|
and dropped `## Core Behavioral Drives` - the assessment table the shipped file carries - so
|
||||||
|
one reset left the file's headings permanently different
|
||||||
|
from every other fork's, with nothing to recreate the table. The anchor now names the real
|
||||||
|
heading and the replacement re-emits it; the skeleton carries the shipped headings in order.
|
||||||
|
`01-candidate-profile.md` and `07-interview-prep.md` were already correct. Two new tests
|
||||||
|
derive both checks from the shipped files, so a renamed heading fails until `/reset`
|
||||||
|
follows it; both fail on master.
|
||||||
|
|
||||||
- **The `/apply` host-check test derives its installed-portal hosts from the skills tree
|
- **The `/apply` host-check test derives its installed-portal hosts from the skills tree
|
||||||
instead of a hand-copied set** (#497, `tests/test_apply_host_check.py`) - `SHIPPED_PORTAL_HOSTS`
|
instead of a hand-copied set** (#497, `tests/test_apply_host_check.py`) - `SHIPPED_PORTAL_HOSTS`
|
||||||
was six names typed into the test and nothing tied it to anything: a portal added by
|
was six names typed into the test and nothing tied it to anything: a portal added by
|
||||||
|
|||||||
@@ -163,6 +163,83 @@ class TestResetCoversEveryPersonalizedSkillFile(unittest.TestCase):
|
|||||||
f"{mislabeled}",
|
f"{mislabeled}",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SKILL_DIR = REPO / ".claude" / "skills" / "job-application-assistant"
|
||||||
|
|
||||||
|
|
||||||
|
def skeleton_block(reset_text, filename):
|
||||||
|
"""The fenced markdown /reset writes over `filename` in Step 3."""
|
||||||
|
marker = f"**For `{filename}`**, replace the file content with:"
|
||||||
|
start = reset_text.index(marker)
|
||||||
|
fence_open = reset_text.index("```markdown", start) + len("```markdown")
|
||||||
|
fence_close = reset_text.index("```", fence_open)
|
||||||
|
return reset_text[fence_open:fence_close]
|
||||||
|
|
||||||
|
|
||||||
|
def h2_headings(text):
|
||||||
|
return [line.strip() for line in text.splitlines() if line.startswith("## ")]
|
||||||
|
|
||||||
|
|
||||||
|
class TestResetTargetsTheHeadingsTheShippedFilesHave(unittest.TestCase):
|
||||||
|
"""Step 3's skeletons and anchors must name sections that exist.
|
||||||
|
|
||||||
|
Two of them drifted from the files they rewrite. The behavioral-profile
|
||||||
|
skeleton used "Strongest Behavioral Traits" / "How I Work Best" / "Growth
|
||||||
|
Areas" where the shipped file has "Strongest Behaviors" / "How You Work
|
||||||
|
Best" / "Growth Areas (frame positively in applications)", and dropped
|
||||||
|
"Core Behavioral Drives" - the structured assessment table /setup collects
|
||||||
|
and /interview reads - so one reset left the file's headings permanently
|
||||||
|
different from every other fork's. The CV-guide step anchored on a line
|
||||||
|
beginning "**Profile statement templates", which the guide has never
|
||||||
|
contained (its heading is "**Create 2-3 profile statement templates for
|
||||||
|
your main role types:**"), so the wipe found nothing and the user's
|
||||||
|
role-tailored statements survived a reset that reported success. Both are
|
||||||
|
derived here from the shipped files, so a renamed heading fails this test
|
||||||
|
until /reset follows it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.reset = RESET.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
def test_full_file_skeletons_keep_the_shipped_headings(self):
|
||||||
|
for filename in ("01-candidate-profile.md", "02-behavioral-profile.md"):
|
||||||
|
with self.subTest(file=filename):
|
||||||
|
shipped = (SKILL_DIR / filename).read_text(encoding="utf-8")
|
||||||
|
self.assertEqual(
|
||||||
|
h2_headings(skeleton_block(self.reset, filename)),
|
||||||
|
h2_headings(shipped),
|
||||||
|
f"/reset's skeleton for {filename} must carry exactly the shipped "
|
||||||
|
"## headings, in order - a reset must not rename or drop sections",
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_partial_anchors_exist_in_the_files_they_target(self):
|
||||||
|
# (reset.md anchor phrase, file, heading the replacement must re-emit)
|
||||||
|
cases = (
|
||||||
|
(
|
||||||
|
r"locate the section that begins with the line `([^`]+)`",
|
||||||
|
"05-cv-templates.md",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
r"The entire `([^`]+)` section",
|
||||||
|
"07-interview-prep.md",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
for pattern, filename in cases:
|
||||||
|
with self.subTest(file=filename):
|
||||||
|
match = re.search(pattern, self.reset)
|
||||||
|
self.assertIsNotNone(match, f"reset.md no longer states its anchor for {filename}")
|
||||||
|
anchor = match.group(1)
|
||||||
|
shipped = (SKILL_DIR / filename).read_text(encoding="utf-8")
|
||||||
|
self.assertIn(
|
||||||
|
anchor,
|
||||||
|
shipped,
|
||||||
|
f"/reset anchors {filename} on {anchor!r}, which the shipped file does not contain - "
|
||||||
|
"the wipe would silently find nothing",
|
||||||
|
)
|
||||||
|
# The replacement block re-emits the anchor line so the heading survives the wipe.
|
||||||
|
step = self.reset[match.start():]
|
||||||
|
block_start = step.index("```markdown") + len("```markdown")
|
||||||
|
block = step[block_start: step.index("```", block_start)]
|
||||||
|
self.assertIn(anchor, block, f"the replacement for {filename} must keep the heading {anchor!r}")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
Reference in new issue
Block a user