name: pb-modify description: Use when modifying PowerBuilder source code (.srw, .srd, .sru, .srm files). Guides the complete workflow from reading to compilation. MUST be used for any PB code change. tools: Glob, Grep, Read, Write, Edit, Bash, TodoWrite
PowerBuilder Code Modification Workflow
CRITICAL RULES — Anti-Hallucination
These rules exist because Claude has caused real compilation failures by hallucinating variable names, control names, and function signatures. Every rule below comes from a real incident.
NEVER invent a variable, control, or function name. If you haven't seen it in the source code via
pb_read_object, it does not exist. The incident withdw_purline_quickfeed(correct name:dw_purlinelimite_quickfeed) cost 3 hours of debugging.NEVER use Edit or Write on .sr files.* These tools corrupt PB encoding (BOM, CRLF, tabs). A PreToolUse hook will block you. Always use
pb_modify_script.NEVER declare a variable without checking existing declarations. The
ld_qtyoldduplicate declaration incident caused a compilation failure that was invisible in Deploy mode.NEVER skip the verification step (Step 5). You MUST re-read the modified file to confirm your change is correct before compiling.
NEVER modify
forward,on create, oron destroysections. These are generated by the PB IDE and will break the object if altered.NEVER guess a DataWindow column name. Use
pb_dw_get_columnsor read the.srdfile to get the actual column names.NEVER copy code between windows without checking control names. Each window has its own controls with specific names. What works in
w_quickpurchasemay reference controls that don't exist inw_quickpurchaselimite.
MANDATORY: Follow ALL steps for EVERY PB code modification
Step 1: Understand — Read Everything First
Before changing any PowerBuilder file, you MUST gather complete context:
- Read the target object using
pb_read_objectto get the FULL source + parsed metadata - Check the inheritance chain using
pb_get_inheritance— what does this inherit from? What inherits from it? - Check dependencies using
pb_get_dependencies— who references this object? What could break? - Get a summary using
pb_get_object_summaryfor a quick structural overview
NEVER modify a PB file without completing all 4 reads above.
Step 2: Inventory — Collect All Names
Before writing any code, build an explicit inventory of names that exist in the target scope. This prevents hallucination of non-existent identifiers.
2a. Variables inventory
From the pb_read_object output, list ALL variables declared in the function/event you're modifying:
- Instance variables (in
type variables ... end variables) - Local variables (declared with
type varnameat the top of the function/event) - Function parameters
CHECK: Is the variable you want to use already declared? If yes, DO NOT re-declare it. CHECK: Does the variable name you're about to use match an existing one EXACTLY? (case-insensitive in PB, but names must match)
2b. Controls inventory
If your code references any UI control (DataWindow, button, text field, etc.), verify it exists:
- Look in the
pb_read_objectoutput for the control'stypedeclaration - For DataWindow controls, confirm the exact name (e.g.,
dw_purlinevsdw_purlinelimite— these are DIFFERENT controls) - If unsure, use
pb_search_codeto find the control name in the source
2c. DataWindow columns inventory
If your code accesses DataWindow columns (via GetItemString, SetItem, GetItemNumber, etc.):
- Use
pb_dw_get_columnsorpb_get_datawindow_sqlto get the actual column list - Or read the
.srdfile directly - NEVER guess a column name — PB gives no error at compile time for wrong column names, it crashes at RUNTIME
2d. Functions inventory
If calling a function on an object:
- Verify the function exists in the object or its ancestor chain via
pb_read_objectorpb_search_code - Check the function signature (parameter types and count)
Step 3: Plan the Modification
Before writing code, state explicitly:
- What you're changing (which event/function/variable)
- Where exactly in the file (after which line/block)
- Names used: list every variable, control, and function your new code references, and confirm each one was found in Step 2
- Ancestor impact: does this change affect behavior inherited by descendants?
If you cannot confirm a name from Step 2, STOP and ask the user or search for it.
Step 4: Apply the Modification
Use pb_modify_script for targeted find-and-replace:
- The tool creates automatic
.bakbackups - The tool verifies unique occurrence before replacing
- The tool normalizes CRLF line endings
- The tool auto-syncs to the
.pbl/subfolder for compilation
For new functions/events, insert at the correct location in the file:
- Instance variables go in
type variables ... end variablessection - Function prototypes go in
forward prototypes ... end prototypes - Functions go after the
end typedeclaration - Events go after functions
IMPORTANT: When modifying similar code in multiple files (e.g., w_quickpurchase AND w_quickpurchaselimite):
- Do NOT copy-paste blindly between files
- Re-read each target file with
pb_read_objectfirst - Re-do the names inventory (Step 2) for EACH file — controls differ between windows
Step 5: Verify — Re-read the Modified File
This step is MANDATORY. Do NOT skip it.
After each pb_modify_script call:
- Re-read the modified file using
pb_read_object(or the specific section withpb_read_object+sectionparameter) - Verify the change is correct: the replacement landed in the right place, no surrounding code was damaged
- Check for duplicates: search for the variable/function name in the full file to ensure you haven't created a duplicate declaration
- Verify the
.pbl/sync:pb_modify_scriptreportspbl_syncedin its output — confirm it's not null
Only proceed to Step 6 if the re-read confirms the modification is correct.
Step 6: Compile and Validate
- Run
pb_validate_syntaxfor quick structural check - Run
pb_compilefor full compilation (uses Full Build by default — gives detailed errors like C0081, C0015) - Read the errors carefully:
C0081: Duplicate variable→ you declared a variable that already existed (Step 2 failure)C0015: Undefined variable→ you used a name that doesn't exist (hallucination)C0114: Error scanning object source entry→ encoding corruption (should not happen withpb_modify_script)C0248: Missing definition of top-level type→$PBExportHeader$orforwardsection damaged
- If compilation succeeds, PBDs auto-copy to the exe directory if
copy_pbds: true
Step 7: Error Recovery
If compilation fails:
- Read the error messages — they tell you EXACTLY what's wrong
- The
.bakbackup file exists — restore withpb_modify_scriptif needed - Go back to Step 2, re-inventory, fix the issue
- Re-compile
- NEVER leave the codebase in a broken compilation state
PowerScript Conventions
Variable naming
is_= instance string,il_= instance long,ib_= instance booleanid_= instance decimal/date,ii_= instance integerls_= local string,ll_= local long,lb_= local boolean,ld_= local decimalas_= argument string,al_= argument long, etc.
Function naming
of_= object function (public method)wf_= window function (private to window)gf_= global function
Event naming
ue_prefix = user-defined events (custom)- Standard events: open, close, clicked, constructor, destructor
Object naming
w_= window,nvo_= non-visual object,uo_= user object (visual)d_= datawindow,m_= menust_= static text,sle_= single line edit,mle_= multi-line editcb_= command button,dw_= datawindow controlddlb_= dropdown list box,rb_= radio button,cbx_= checkbox
File structure (.sr* files)
$PBExportHeader$objectname.srw
forward ← DO NOT MODIFY
global type ... from ...
end type
end forward
shared variables ← shared across instances
end variables
type variables ← instance variables
end variables
forward prototypes ← function declarations
end prototypes
type prototypes ← more declarations
end prototypes
event open;...end event ← events
public function ...end function ← functions
on objectname.create ← lifecycle — DO NOT MODIFY
on objectname.destroy ← lifecycle — DO NOT MODIFY
Common patterns
SQLCA= default transaction object (database connection)- After ANY SQL statement, ALWAYS check
SQLCA.SQLCode(1 = success, -1 = error) this.= current object,parent.= parent windowdestroy= free memory for dynamic objects (MUST be called or memory leaks)trigger event= fire event now,post event= queue for later
Checklist Summary
Before submitting your modification, verify:
[ ] Step 1: Read object, inheritance, dependencies, summary — ALL DONE
[ ] Step 2: All variable names confirmed from source (not invented)
[ ] Step 2: All control names confirmed from source (not invented)
[ ] Step 2: All DW column names confirmed (not guessed)
[ ] Step 2: All function names/signatures confirmed
[ ] Step 3: Plan stated with explicit name list
[ ] Step 4: Used pb_modify_script (NOT Edit/Write)
[ ] Step 5: Re-read modified file — change is correct
[ ] Step 5: No duplicate declarations introduced
[ ] Step 5: pbl_synced confirmed
[ ] Step 6: pb_compile succeeded (Full Build)
[ ] Step 7: No errors left — codebase compiles clean