file_patch was working — Part 41 covered the basics. But it had a fundamental usability problem on the planner side. To patch a file, the planner needs to specify an anchor: a unique string in the existing file that tells file_patch where to insert or replace. The planner has to read the file, find a suitable string, verify it’s unique, and include it in the plan. This is structural reasoning (where should the change go?) mixed with mechanical string-hunting (what text is unique near that location?).
The planner is good at structural reasoning. It can identify that a new weather panel should go after the navigation section, or that a CSS rule should be added inside a specific media query. But the mechanical part — scanning file content for a unique substring — is exactly the kind of task where LLMs make mistakes. They hallucinate strings that don’t exist in the file. They pick strings that appear multiple times. They choose strings that are technically unique but semantically wrong — anchoring to a comment instead of the structural element.
The anchor allocator removes the mechanical part entirely. After the code fixer runs on a file, the allocator parses the file’s structure and inserts named marker comments at structural boundaries. In HTML: <!-- anchor: el-panel-weather --> before a div, <!-- anchor: el-panel-weather-end --> after it. In Python: # anchor: func-fetch_data before a function definition. In CSS: /* anchor: media-desktop */ before a media query.
The naming is semantic where possible. Elements with IDs become el-{id}. Named functions become func-{name}. Classes become class-{name}. When there’s no semantic identifier, positional fallback kicks in: el-nav-1, block-3. Start/end pairs enable range operations — replacing everything between el-panel-weather and el-panel-weather-end replaces the entire panel without the planner needing to specify the closing tag.
Parsing is language-specific. HTML uses BeautifulSoup for AST-level structure. Python uses the ast module. CSS, Shell, YAML, and TOML use regex and stdlib parsers. JSON is the exception — no comment syntax means no markers can be inserted, but the structure is still extracted for the anchor map. Each parser follows the same interface: parse, identify structural boundaries, return anchor entries with tier classifications (section, block, detail).
The allocator is designed to be idempotent. Running it twice on the same file produces identical output. This is achieved by always stripping existing anchors before re-allocating — no accumulation, no drift. If the file changes outside the pipeline, the content hash changes, and the stale anchor map is discarded on the next allocation.
Anchor maps are stored in episodic memory as structured facts. A partial unique index on (fact_type, file_path, user_id) enables atomic upserts without delete-then-insert races. When the planner reads a file during planning, the corresponding anchor map is included in the context. Instead of scanning for unique strings, the planner selects from a menu of named positions.
The planner prompt was updated with examples. Good: “Use anchor el-panel-weather for insertion.” Bad: “Use the text <div class='panel'> as anchor.” The fallback path remains — if no anchor map exists (new file, unsupported format), the planner reverts to manual anchor selection. But for the common cases — HTML, Python, CSS — the map is available and the planner uses it.
Six runtime bugs surfaced during deployment. file_patch crashing when content was None. A NameError where user_id wasn’t in scope for the episodic store call. Duplicate end markers in the HTML parser. Silent failures where logging wasn’t surfacing allocator errors. Each one was the kind of integration bug that unit tests don’t catch — the allocator worked in isolation, but the wiring between allocator, executor, and episodic store had gaps.
The result is measurable. Anchor selection failures — the planner picking a non-existent or non-unique string — were one of the most common causes of file_patch failures and cascading corruption. With named anchors, the planner is choosing from a verified list rather than inventing strings. The mechanical task is gone. The structural reasoning remains, which is what the planner is actually good at.