Files
LithosAnanake/docs/working/archive/operations/refinement/annotations.adoc
T

628 lines
16 KiB
Plaintext

// Moved from docs/05-operations/refinement/annotations.adoc to docs/working/archive/operations/refinement/annotations.adoc on 2026-06-16 (docs reorg Phase 2)
= StarForth Refinement Code Annotation Guide
:toc: left
:toclevels: 2
:sectnums:
:source-highlighter: rouge
:icons: font
== Overview
This guide standardizes how C code is annotated to map to Isabelle formal specifications.
**Goal:** Make the correspondence between implementation and theory explicit and verifiable.
**Scope:** Every function in scope for refinement verification gets annotated.
---
== Annotation Standards
=== File Header Annotation
Every C source file undergoing refinement should begin with a refinement mapping header:
[source,c]
----
/**
* ============================================================================
* FILE: vm.c
* REFINEMENT TARGET: VM core execution semantics
*
* This file implements the following Isabelle theories:
* - VM_Core.thy .................. Core VM state and instruction execution
* - VM_Stacks.thy ................ Data and return stack operations
* - VM_StackRuntime.thy .......... Stack runtime invariants
* - VM_Register.thy .............. Register and program counter management
*
* REFINEMENT STATUS: PHASE 1 IN-PROGRESS
* RELATED CAPAs: DEFECT-001, DEFECT-002, DEFECT-003
* LAST VERIFIED: 2025-10-30
*
* NOTATION:
* REFINEMENT: Code path → Isabelle definition (precondition/postcondition)
* INVARIANT: Property that must hold after execution
* TODO_PROOF: Refinement proof still needed
* ============================================================================
*/
----
=== Function Header Annotation
Every function with an Isabelle counterpart gets this pattern:
[source,c]
----
/**
* REFINEMENT: VM_Stacks.thy::push (line 42)
*
* Implements the abstract stack push operation.
*
* C Signature: void stack_push(vm_state_t *state, uint16_t value)
* Theory Signature: push :: nat → vm_state → vm_state
*
* Preconditions (must be verified by caller or this function):
* - dsp < STACK_MAX - 1 (stack has room)
* - state is valid (initialized)
*
* Postconditions (guaranteed after execution):
* - If precondition held: dsp increased by 1, value stored
* - If precondition violated: error flag set, state unchanged
* - 0 ≤ dsp < STACK_MAX always (INVARIANT)
*
* Related CAPAs: DEFECT-001 (stack bounds)
* Proof Status: TODO_PROOF (see StarForth_Refinement.thy line NNN)
*/
void stack_push(vm_state_t *state, uint16_t value) {
// Implementation
}
----
=== Inline Code Annotations
For critical code sections, add inline comments mapping to theory:
[source,c]
----
void stack_push(vm_state_t *state, uint16_t value) {
// REFINEMENT PRECONDITION CHECK
// Theory requires: dsp < STACK_MAX - 1
// Code enforces:
if (state->dsp >= STACK_MAX - 1) {
// REFINEMENT: Error case from theory
// Corresponds to theory's error_push case
state->error = VM_ERROR_STACK_OVERFLOW;
return; // Failure path - state unchanged
}
// REFINEMENT SUCCESS PATH
// This corresponds exactly to theory_push:
// dsp' = dsp + 1
// stack'[dsp'] = value
state->data_stack[++state->dsp] = value;
state->error = VM_ERROR_NONE;
// INVARIANT: 0 ≤ dsp < STACK_MAX
// Verified by: precondition check above + increment operation
}
----
---
== Annotation Patterns by Type
=== Pure Functions
Functions that are deterministic, no side effects:
[source,c]
----
/**
* REFINEMENT: VM_DataStack_Words.thy::dup_top (line 89)
* Pure function: input → output (no state modification)
*
* Theory: dup_top(stack: list) → list
* Code: duplicates top of stack
*
* Precondition: stack not empty
* Postcondition: top element duplicated
*/
uint16_t dup_top(const uint16_t *stack, size_t sp) {
return stack[sp]; // Simply return top element
}
----
=== State Transformation Functions
Functions that modify VM state:
[source,c]
----
/**
* REFINEMENT: VM_Core.thy::execute_instr (line 156)
* State transformation: vm_state → vm_state
*
* Theory: execute_instr(state, instr) → state'
* Code: Modifies state based on instruction
*
* Precondition: state valid, instruction valid
* Postcondition: state updated per instruction semantics
* Invariant: 0 ≤ pc < PROGRAM_SIZE (maintained)
*/
void execute_instruction(vm_state_t *state, uint16_t instr) {
// Get opcode (high byte)
uint8_t opcode = (instr >> 8) & 0xFF;
// Get argument (low byte)
uint8_t arg = instr & 0xFF;
// REFINEMENT: Case analysis over all opcodes
// Each case corresponds to theory's instr_case in exec_instr
switch(opcode) {
case OP_PUSH:
// REFINEMENT: Corresponds to theory_push_instr
stack_push(state, arg);
state->pc++;
break;
case OP_DUP:
// REFINEMENT: Corresponds to theory_dup_instr
// (Details in VM_DataStack_Words.thy line 89)
code_dup(state);
state->pc++;
break;
// ... more cases ...
}
// INVARIANT: PC always incremented (unless jump/call)
// INVARIANT: error flag set iff operation failed
}
----
=== Functions with Multiple Theories
When one C function implements multiple theory operations:
[source,c]
----
/**
* REFINEMENT: Multiple theories
* - VM_StackRuntime.thy::stack_pop_safe (line 234)
* - VM_Stacks.thy::pop (line 51)
* - VM_Core.thy::pop_error_handling (line 78)
*
* This function implements both:
* 1. The abstract pop operation
* 2. The error handling for underflow
*/
void stack_pop(vm_state_t *state, uint16_t *out) {
if (state->dsp == 0) {
// REFINEMENT: Theory case pop_empty from VM_StackRuntime.thy
state->error = VM_ERROR_STACK_UNDERFLOW;
return;
}
// REFINEMENT: Theory case pop_nonempty from VM_Stacks.thy
*out = state->data_stack[state->dsp--];
state->error = VM_ERROR_NONE;
}
----
=== Functions with Helper Lemmas
When a function needs auxiliary lemmas to verify:
[source,c]
----
/**
* REFINEMENT: VM_Words.thy::add_word (line 201)
*
* Note: This refinement requires auxiliary lemmas:
* - add_preserves_bounds (add doesn't overflow 16-bit bounds)
* - add_commutative (proven in theory)
* - stack_push_pop_inverse (proven in VM_Stacks.thy)
*
* Proof location: StarForth_Refinement.thy, lemmas:
* - code_add_refines_theory_add
* - add_word_error_handling
*/
void code_add(vm_state_t *state) {
uint16_t b = stack_pop_unchecked(state);
uint16_t a = stack_pop_unchecked(state);
uint16_t result = a + b;
stack_push(state, result);
}
----
=== Partially Implemented Functions
When theory-code correspondence is incomplete/evolving:
[source,c]
----
/**
* REFINEMENT: VM_Core.thy::exec_instr (PARTIAL)
*
* TODO_PROOF: This function is still being refined.
* Current status:
* ✅ PUSH instruction: complete proof
* ⚠️ DUP instruction: proof in progress (DEFECT-003)
* ❌ DROP instruction: not yet matched to theory
*
* Related CAPAs:
* - DEFECT-003: Instruction dispatch mapping
* - DEFECT-004: DROP operation missing from theory
*
* Do NOT trust this function for auditing until all cases verified.
*/
void execute_instruction(vm_state_t *state, uint16_t instr) {
// ...
}
----
---
== Cross-Reference Patterns
=== Theory → Code References
In Isabelle theory files, add comments linking back to C:
[source,isabelle]
----
(* REFINEMENT: This definition is implemented in C as:
File: src/vm.c, line 145
Function: stack_push()
See: docs/REFINEMENT_CAPA.adoc::DEFECT-001
*)
definition push :: "nat ⇒ vm_state ⇒ vm_state" where
"push val state =
state⦇data_stack := (data_stack state) @ [val],
dsp := dsp state + 1⦈"
----
=== Code → Theory References
In C code, reference theory line numbers:
[source,c]
----
// REFINEMENT: VM_Stacks.thy line 42
// See: definition push :: "nat ⇒ vm_state ⇒ vm_state"
void stack_push(vm_state_t *state, uint16_t value) {
----
---
== Invariant Documentation
=== Global Invariants
Add to vm.h or appropriate header:
[source,c]
----
/**
* REFINEMENT INVARIANTS
* These properties must hold after every operation.
* They are proven in the Isabelle theories.
*
* INV-001: Stack Bounds
* 0 ≤ dsp < STACK_MAX AND 0 ≤ rsp < STACK_MAX
* Theory: VM_StackRuntime.thy::stack_bounds_invariant
*
* INV-002: PC Validity
* 0 ≤ pc < PROGRAM_SIZE OR pc == HALT_PC
* Theory: VM_Core.thy::pc_validity
*
* INV-003: Error State Consistency
* error ≠ NONE ⟹ last operation failed
* error = NONE ⟹ last operation succeeded
* Theory: VM_Core.thy::error_consistency
*
* These are maintained by every operation.
* If any operation violates them, it's a bug in either:
* - The code (implementation wrong)
* - The theory (specification was wrong)
*/
----
=== Per-Function Invariants
[source,c]
----
void stack_push(vm_state_t *state, uint16_t value) {
// On entry: INV-001, INV-002, INV-003 hold
if (state->dsp >= STACK_MAX - 1) {
state->error = VM_ERROR_STACK_OVERFLOW;
// On exit (error path): INV-001, INV-002, INV-003 still hold
return;
}
state->data_stack[++state->dsp] = value;
state->error = VM_ERROR_NONE;
// On exit (success path): INV-001, INV-002, INV-003 still hold
}
----
---
## Error Handling Patterns
=== Explicit Error Cases
[source,c]
----
/**
* REFINEMENT: Error handling per VM_Core.thy::error_cases
*
* All operations return error status via state->error.
* Errors are NOT exceptions; they're part of the state machine.
*
* Theory models error as:
* type error_flag = OK | STACK_OVERFLOW | STACK_UNDERFLOW | INVALID_INSTR
*
* Code maps to:
* VM_ERROR_NONE → OK
* VM_ERROR_STACK_OVERFLOW → STACK_OVERFLOW
* VM_ERROR_STACK_UNDERFLOW → STACK_UNDERFLOW
* VM_ERROR_INVALID_INSTRUCTION → INVALID_INSTR
*/
----
=== Precondition Violations
[source,c]
----
/**
* REFINEMENT: Precondition checking
*
* If a function has preconditions in the theory (e.g., "stack not empty"),
* the C code must either:
*
* A) Verify the precondition and return error if violated
* (Error handling code path)
*
* B) Assume caller verified it (assert in debug builds)
* (Unsafe - must document clearly)
*
* For refinement, we recommend option A.
*/
----
---
## Proof Status Markers
Use these consistently:
[source,c]
----
// ✅ PROVEN: This refinement is proven in Isabelle
// Proof: StarForth_Refinement.thy::code_push_refines_theory_push
// ⚠️ IN-PROGRESS: Proof is being worked on
// Proof attempt at: StarForth_Refinement.thy line 456
// Issue: DEFECT-001
// ❌ TODO_PROOF: Refinement proof needed but not started
// Theory: VM_Core.thy::exec_instr
// CAPA: DEFECT-003
// 📋 NOT-APPLICABLE: No Isabelle counterpart for this code
// Reason: Helper/utility function (logging, debugging)
// OK to leave unproven
----
---
## Checklist for Annotating a Function
Use this when adding annotations to existing C code:
[source]
----
☐ 1. Find the Isabelle theory this implements
Theory name: _________________
Definition/lemma: ____________
Line number: __________________
☐ 2. Write function header with REFINEMENT block
C signature documented
Theory signature documented
Preconditions listed
Postconditions listed
☐ 3. Add inline comments for:
Precondition checks
Success/failure paths
Invariant maintenance
☐ 4. Set proof status marker
☐ ✅ PROVEN (reference proof)
☐ ⚠️ IN-PROGRESS (reference CAPA)
☐ ❌ TODO_PROOF (reference theory)
☐ 📋 NOT-APPLICABLE (explain why)
☐ 5. Cross-reference the CAPA document
Related defect(s): ___________
Resolution plan: _____________
☐ 6. Create/update Isabelle proof
File: StarForth_Refinement.thy
Lemma: code_FUNCTION_refines_theory_FUNCTION
Status: started / in-progress / complete
----
---
## Example: Full Annotation
Here's a complete, fully-annotated example:
[source,c]
----
/**
* ============================================================================
* FUNCTION: stack_push()
* ============================================================================
*
* REFINEMENT: VM_Stacks.thy::push (line 42)
*
* Implements: abstract stack push operation from formal specification
* Purpose: Add element to data stack, maintaining size invariants
*
* SIGNATURES:
* C code: void stack_push(vm_state_t *state, uint16_t value)
* Isabelle: push :: nat ⇒ vm_state ⇒ vm_state
*
* PRECONDITIONS (must hold before call):
* 1. state ≠ NULL (valid pointer)
* 2. dsp < STACK_MAX - 1 (room for one more element)
* Verified by: this function checks #2; caller ensures #1
*
* POSTCONDITIONS (guaranteed after return):
* On success:
* - dsp increased by exactly 1
* - stack[dsp] = value (new top element)
* - error = VM_ERROR_NONE
* - All invariants maintained
*
* On error (dsp overflow):
* - dsp unchanged
* - stack unchanged
* - error = VM_ERROR_STACK_OVERFLOW
* - All invariants maintained
*
* RELATED CAPA ENTRIES:
* - DEFECT-001: Stack Push Error Handling
* Status: IN-PROGRESS
* Issue: Precondition checking formalization
*
* PROOF STATUS: ⚠️ IN-PROGRESS
* Proof location: docs/src/internal/formal/StarForth_Refinement.thy
* Lemma: stack_push_refines (line 156)
* Dependencies:
* - lemma stack_bounds_preserved
* - lemma error_flag_consistency
* Blockers: None
*
* INVARIANTS MAINTAINED:
* - INV-001 (Stack Bounds): 0 ≤ dsp < STACK_MAX
* - INV-003 (Error Consistency): error ≠ NONE ↔ operation failed
*
* RELATED FUNCTIONS:
* - stack_pop() (inverse operation)
* - stack_push_unchecked() (unsafe version, NOT for refinement)
*
* VERSION HISTORY:
* 2025-10-30: Initial annotation, proof in progress
*/
void stack_push(vm_state_t *state, uint16_t value) {
// REFINEMENT PRECONDITION CHECK
// Theory: push requires dsp < STACK_MAX - 1
// Code implementation:
if (state->dsp >= STACK_MAX - 1) {
// FAILURE PATH: Corresponds to theory's push_overflow case
// Theory: error_push :: "dsp >= STACK_MAX - 1 ⟹ error = STACK_OVERFLOW"
state->error = VM_ERROR_STACK_OVERFLOW;
return; // State unchanged on error
}
// SUCCESS PATH: Corresponds to theory's push_ok case
// Theory equations to verify:
// dsp' = dsp + 1
// stack'[dsp'] = value
// error' = OK
state->data_stack[++state->dsp] = value; // REFINEMENT: This matches "dsp' = dsp + 1"
state->error = VM_ERROR_NONE; // REFINEMENT: error' = OK
// INVARIANT CHECK: 0 ≤ dsp < STACK_MAX
// Justified:
// - dsp was < STACK_MAX - 1 (from precondition check above)
// - We incremented dsp by 1
// - Therefore dsp ≤ STACK_MAX - 1, i.e., dsp < STACK_MAX ✓
// - dsp ≥ 0 (was ≥ 0 before, still ≥ 0 after increment) ✓
}
----
---
## Tools & Automation
=== grep for Finding Annotations
[source,bash]
----
# Find all REFINEMENT annotations
grep -r "REFINEMENT:" src/
# Find all TODO_PROOF items
grep -r "TODO_PROOF" src/
# Find functions without annotations
grep -r "^void " src/ | grep -v "^[[:space:]]*//" | grep -v "REFINEMENT"
----
=== Validation Script
Create `scripts/check-refinement-annotations.sh`:
[source,bash]
----
#!/bin/bash
# Check that all functions in phase 1 scope have REFINEMENT annotations
PHASE1_FUNCTIONS=(
"stack_push"
"stack_pop"
"execute_instruction"
"execute_call"
"execute_return"
)
for func in "${PHASE1_FUNCTIONS[@]}"; do
if ! grep -q "REFINEMENT.*$func" src/vm.c; then
echo "ERROR: Function $func missing REFINEMENT annotation"
exit 1
fi
done
echo "✅ All Phase 1 functions have refinement annotations"
----
---
## Version Control
When committing annotated code:
[source]
----
Commit message format:
docs(refinement): Annotate vm.c stack operations
- Add REFINEMENT header to stack_push() (DEFECT-001)
- Add REFINEMENT header to stack_pop() (DEFECT-002)
- Add proof status markers
- Link to Isabelle lemmas in StarForth_Refinement.thy
Related: DEFECT-001, DEFECT-002
Theory: VM_Stacks.thy
----
---
== Summary
Good refinement annotations enable:
- ✅ Auditors understand code-theory correspondence - ✅ Developers track proof status without external documents - ✅ Automated tools to find gaps - ✅ Clear assignment of responsibilities - ✅ Traceable defect-to-proof links
Follow this guide consistently, and your code becomes a bridge between implementation and specification.
Generated: {docdate}