Promotions at One Employer: How ATS Parses Stacked Roles

You were promoted twice at the same company, and the ATS now says you had three employers, two of them called "Senior Software Engineer" with no dates, or worse, it shows one job that began the day of your last promotion. Promotions are the strongest career signal a resume can carry, and they are also one of the layouts parsers mangle most often. The fix is a layout that keeps one employer, several titled roles, and a date range on every role.
I build Smart Resume Analyzer, an ATS resume checker, and I have spent nine years as a Principal Software Engineer in Karachi writing parsing and matching code in PHP, Laravel, Vue, Nuxt, Node and TypeScript. I wrote this with help from AI tools and checked every example and claim myself. This piece covers one problem: showing promotions and internal moves at one employer so ATS software records every role, every title and the full tenure.
How do you list promotions at the same company for ATS?
Direct answer: Write the employer name once, then list each role underneath as its own line with a title and its own month-year date range, newest first. Give every role two to four bullets. Never leave a title without dates, and never merge all roles into one date range, because parsers attach dates to titles, not to employers.
Why stacked roles break parsers
Most parsers build a work-history row from three things that sit close together: an organization, a title, and a date range. A stacked layout breaks that pattern on purpose. The organization appears once, and the titles below it have no organization next to them. What happens next depends on how the parser groups lines.
| Layout | What the parser usually sees | Typical result | Risk |
|---|---|---|---|
| Employer once, each role with its own dates | One organization, several title + date pairs | Several rows with the same employer, or one row with sub-positions | Low |
| Employer once, dates only on the employer line | Titles with no dates | Only the top title kept; lower titles dropped or dumped into description text | High: promotions disappear |
| Employer repeated on every role | Separate jobs with identical names | Several rows, each correct | Low for parsing, but reads like job changes to a skimming human unless the titles show progression |
| All titles on one line ("Engineer → Senior → Lead") | One title string with arrows | Title field filled with the whole string; title search may miss it | Medium |
| Roles in a table or two columns | Text read row by row or column by column | Titles and dates mismatched | High |
The second row is the one I see most. People put "2018 – Present" next to the company name, which feels clean, and then list three titles with no dates. The parser has nowhere to put those titles.
How the major ATS products handle it
Treat these as working assumptions, not vendor guarantees. Each employer configures its own instance, and parsing engines change.
| ATS | What to expect | What to check |
|---|---|---|
| Workday | Parsed into "Work Experience" rows that you review on the application form | Count the rows. Each role should have its own row with the right title and dates; fix or add rows by hand before you submit |
| Greenhouse | Resume parsed into the profile, and the original file stays searchable | Title wording matters for search, so keep each title on its own line |
| Lever | Profile fields plus the attached resume | Keep company and the top title close together so the headline reads correctly |
| iCIMS | Configurable work-history fields, sometimes with a "current employer" question | Your current title should be the first role under the employer |
| Taleo | Experience blocks that candidates often edit | A role without its own dates line tends to merge into the role above |
Workday matters most here, because the parsed rows are shown back to you. If you see one row where you expected three, the parser did not understand your layout, and recruiters searching structured fields will not see your earlier titles.
What the parser does with your lines
Here is a simplified version of the grouping logic. Real engines are more forgiving, but the failure shape is the same.
import re DATES = re.compile(r"((?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\w* \d{4})\s*[-–]\s*(Present|(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\w* \d{4})") def group_roles(lines): roles, org = [], None for line in lines: m = DATES.search(line) text = DATES.sub("", line).strip(" |,–-") if m and org is None: org = text roles.append({"org": org, "title": None, "start": m[1], "end": m[2]}) elif m: roles.append({"org": org, "title": text, "start": m[1], "end": m[2]}) elif org is None: org = text else: roles.append({"org": org, "title": text, "start": None, "end": None}) return roles weak = ["Northwind Systems | Jan 2019 – Present", "Engineering Manager", "Senior Software Engineer", "Software Engineer"] strong = ["Northwind Systems, Karachi", "Engineering Manager | Mar 2024 – Present", "Senior Software Engineer | Jun 2021 – Feb 2024", "Software Engineer | Jan 2019 – May 2021"] for r in group_roles(weak): print(r) print("---") for r in group_roles(strong): print(r) Output:
{'org': 'Northwind Systems', 'title': None, 'start': 'Jan 2019', 'end': 'Present'} {'org': 'Northwind Systems', 'title': 'Engineering Manager', 'start': None, 'end': None} {'org': 'Northwind Systems', 'title': 'Senior Software Engineer', 'start': None, 'end': None} {'org': 'Northwind Systems', 'title': 'Software Engineer', 'start': None, 'end': None} --- {'org': 'Northwind Systems, Karachi', 'title': 'Engineering Manager', 'start': 'Mar 2024', 'end': 'Present'} {'org': 'Northwind Systems, Karachi', 'title': 'Senior Software Engineer', 'start': 'Jun 2021', 'end': 'Feb 2024'} {'org': 'Northwind Systems, Karachi', 'title': 'Software Engineer', 'start': 'Jan 2019', 'end': 'May 2021'} In the weak layout, the dates attach to an empty title, and three titles have no dates. A system that calculates time in role, or that filters for "two years as Senior Software Engineer", has nothing to work with. In the strong layout, every row is complete. Dates are the most fragile field on any resume, which I covered in how ATS parses employment dates and gaps.
Weak vs. ATS-Optimized rewrites
| Weak | ATS-Optimized | Why it works |
|---|---|---|
Northwind Systems — 2019–Present then three undated titles | Employer line, then Engineering Manager — Mar 2024 – Present, Senior Software Engineer — Jun 2021 – Feb 2024, and so on | Every title gets its own date range |
Software Engineer → Senior → Engineering Manager | Three separate role lines | Each title is searchable on its own |
Promoted to Senior in 2021 as a bullet | Senior Software Engineer — Jun 2021 – Feb 2024 as a role line, plus one bullet on why | A bullet is description text; a role line becomes a structured title |
| Same bullets repeated under every role | Different bullets per role, showing growing scope | Shows progression instead of padding |
Lead (acting) with no dates | Acting Team Lead — Sep 2023 – Feb 2024 | Honest label, still parseable |
| Internal transfer written as a new company | Northwind Systems (Payments team) then (Platform team) under one employer | Avoids looking like a job change |
The title itself still has to match how recruiters search. If your internal title is unusual, the advice in how ATS search matches your resume job titles applies to each stacked role.
Stack or repeat? A decision framework
Use the stacked layout (employer once) by default. Repeat the employer on each role only when:
- The roles were in different legal entities or brands. A move from a parent company to a subsidiary is two employers. Write both names.
- There was a gap. If you left and came back, it is two separate jobs with a gap, and the dates should say so.
- A form asks for it. Some application forms want one row per position with the employer filled in every time. Follow the form.
For very short stints, such as a three-month acting role, it is fine to fold it into a bullet under the main role instead of giving it a line. Use the same judgment I described for contractor and agency roles: group what belongs together, but never hide dates.
Bullets that prove the promotion
A promotion is a claim. The bullets under each role are the evidence. Write them so scope grows from the bottom role to the top one:
- Earliest role: what you built or owned. "Built the invoice export service used by finance."
- Middle role: what you led or improved across a team. "Led a three-engineer rewrite of billing; cut month-end close from four days to one."
- Latest role: what you decided, hired for, or changed for the organization. "Hired and onboarded five engineers; set the on-call process the team still uses."
Only use numbers you can back up in an interview.
Diagnostic checklist: 10 minutes before you submit
- Write the employer line once, with location if you use it elsewhere.
- Give every role its own line: title, delimiter, month-year start, month-year end or "Present".
- Order roles newest first, matching the rest of the resume.
- Check end and start dates so they meet or overlap only when that is true.
- Give each role two to four bullets that do not repeat each other.
- Avoid tables, columns and arrows in the role lines.
- Copy the PDF text into a plain editor and confirm each role is on its own line with its dates.
- Re-parse the file with an ATS-style checker such as my Workday resume checker and count the work-history rows.
- On Workday-style forms, review every parsed row and fix titles or dates before submitting.
Pre-submit checklist
- [ ] One employer line, several role lines
- [ ] Every role has a title and month-year dates
- [ ] No arrows, tables or columns in role lines
- [ ] Bullets show growing scope, not repeated text
- [ ] Parsed output shows one row per role
Frequently asked questions
Should I list each promotion as a separate job?
List each promotion as a separate role with its own title and dates, under one employer line. That gives parsers complete rows and shows a human the progression at a glance.
What if my promotion came with no title change?
Then it is not a new role line. Mention the change in a bullet, such as a new level or a larger scope, and keep the title as it was.
Will repeating the company name look like job hopping?
To a parser, no. To a skimming recruiter, it can if the titles do not show progression. The stacked layout avoids the question.
How do I show an internal transfer to another team?
Keep the same employer and add the team in brackets on each role line, for example "Senior Engineer (Payments)" and "Senior Engineer (Platform)", each with its own dates.
Does the ATS calculate total years at the company?
Some instances calculate time from parsed rows, and some do not. You cannot rely on either, so make every row complete and let the dates speak for you.
What about acting or interim roles?
Label them honestly, such as "Acting Team Lead", and give them dates. If the stint was very short, a bullet under the main role is enough.
Follow & Connect
- YouTube: Resume Boost AI (@resume-boost-ai)
- TikTok: Resume Boost AI (@resumeboostai)
- X: Muhammad Ali Mughal (@AliMughal887)
- GitHub: Muhammad Ali Mughal (@ali111887)
- LinkedIn: Muhammad Ali Mughal
原文:https://www.a8q9.cn/en/article/promotions-at-one-employer-how-ats-parses-stacked-roles-38ba39.html