Context
I have been using these coding preferences with little to no issues. In this session, the model Astra seemed to trip over them repeatedly while implementing spences10/pirecall#59.
That experience matters: this is not a claim that the preferences have generally been unusable. The investigation found a deterministic false positive in the configured naming rule, compounded by the model repeatedly guessing at workarounds rather than identifying the trigger. Whether Astra produces these triggering patterns more often than other models has not been measured.
Verified cause
The global prefer-project-snake-case-identifiers rule in ~/.pi/agent/my-pi-settings.json targets write and edit inputs. Its pattern is:
\b(?:const|let|var|function)\s+[a-z][A-Za-z0-9_]*[A-Z][A-Za-z0-9_]*\b|\b(?:interface|type|class|enum)\s+[a-z][A-Za-z0-9_]*\b
packages/pi-coding-preferences/src/index.ts applies each regex to strings returned by extract_input_strings in packages/pi-settings/src/index.ts. This is raw text matching, not syntax-aware identifier checking. For edits, both oldText and newText are scanned.
Consequently, ordinary prose inside string literals is mistaken for a lowercase type declaration:
| Input |
Actual match |
Result |
throw new Error('--type must be user, assistant, toolResult, or all'); |
type must |
Blocked |
test('type combines with project, session, date, sort, and limit', () => {}); |
type combines |
Blocked |
import { runCommand } from 'citty'; |
None |
Allowed |
const badName = 1; |
const badName |
Blocked as intended |
const good_name = 1; |
None |
Allowed |
This naming rule is locally configured; it is not in the package's built-in default_config.
Evidence from the session
Replayed all 11 edit/write calls through the exported should_block_coding_preference function using the current configuration. Every replay matched the recorded blocked/allowed outcome:
- Five CLI edit attempts blocked on
type must in an error-message string.
- One test edit and one test-file write blocked on
type combines in a test title.
- Four other edits allowed.
The tool response only reported the generic coding-style reason, without the matched text, rule name, input field, or location.
The model guessed that external camelCase API names might be responsible and attempted aliases such as runCommand as run_command. runCommand was never a trigger, and the alias did not address the problem. The user stopped the attempts and reverted the application changes.
Expected behaviour / proposed follow-up
- Naming enforcement should distinguish project-owned declarations from strings, comments, and external/package API names; use syntax-aware checks rather than interpreting arbitrary prose as declarations.
- Define edit semantics so existing text in
oldText does not prevent correcting a violation.
- Improve block diagnostics with the rule name and input field/location. If exposing matched text, keep it bounded and redact or suppress sensitive matches.
- Add regression coverage for the examples above, including both single and batched edits, while preserving rejection of actual naming violations.
- Review the agent-side response to opaque blocks: stop unsupported workaround attempts and report the uncertainty instead of changing valid external API names.
No harness settings or source files were changed during the investigation.
Context
I have been using these coding preferences with little to no issues. In this session, the model Astra seemed to trip over them repeatedly while implementing spences10/pirecall#59.
That experience matters: this is not a claim that the preferences have generally been unusable. The investigation found a deterministic false positive in the configured naming rule, compounded by the model repeatedly guessing at workarounds rather than identifying the trigger. Whether Astra produces these triggering patterns more often than other models has not been measured.
Verified cause
The global
prefer-project-snake-case-identifiersrule in~/.pi/agent/my-pi-settings.jsontargetswriteandeditinputs. Its pattern is:packages/pi-coding-preferences/src/index.tsapplies each regex to strings returned byextract_input_stringsinpackages/pi-settings/src/index.ts. This is raw text matching, not syntax-aware identifier checking. For edits, botholdTextandnewTextare scanned.Consequently, ordinary prose inside string literals is mistaken for a lowercase type declaration:
throw new Error('--type must be user, assistant, toolResult, or all');type musttest('type combines with project, session, date, sort, and limit', () => {});type combinesimport { runCommand } from 'citty';const badName = 1;const badNameconst good_name = 1;This naming rule is locally configured; it is not in the package's built-in
default_config.Evidence from the session
Replayed all 11 edit/write calls through the exported
should_block_coding_preferencefunction using the current configuration. Every replay matched the recorded blocked/allowed outcome:type mustin an error-message string.type combinesin a test title.The tool response only reported the generic coding-style reason, without the matched text, rule name, input field, or location.
The model guessed that external camelCase API names might be responsible and attempted aliases such as
runCommand as run_command.runCommandwas never a trigger, and the alias did not address the problem. The user stopped the attempts and reverted the application changes.Expected behaviour / proposed follow-up
oldTextdoes not prevent correcting a violation.No harness settings or source files were changed during the investigation.