MODULE 15 · 5 HOUR BUILD
Inspectable invoice browser workflow
Build a browser workflow harness that records observations, proposals, preconditions, and persisted outcomes. The seed simulates a tiny invoice application without a browser or network.
Build evidence Record your actual checks, results, and limitations.
Build it in stages
- Define observation and action schemas with revision and invoice identity.
- Add ambiguous controls, hidden controls, and stale-state fixtures.
- Implement observe, propose, validate, execute, and verify stages.
- Export a claim and action trace for each fixture case.
- Optionally replace the simulated page with a local Playwright fixture after installing Playwright and its browser separately.
Your acceptance criteria
Use these as your project review. Record commands, outputs, and failure cases in your repository.
- A stale proposal performs zero writes.
- A valid save updates only the selected invoice.
- Every success includes a checked record value.
- Ambiguous targets and injected page instructions produce explicit diagnostic records.
A working starting point
The seed runs as supplied. Extend it to satisfy the full brief. It is a teaching starting point, not a finished portfolio submission.
main.py
python
from copy import deepcopy
class InvoiceApp:
def __init__(self):
self.revision = 1
self.records = {'42': {'reference': 'OLD'}, '99': {'reference': 'KEEP'}}
self.trace = []
def observe(self, invoice):
return {'revision': self.revision, 'invoice': invoice,
'record': deepcopy(self.records[invoice])}
def save(self, proposal):
if proposal['revision'] != self.revision:
self.trace.append('blocked: stale proposal')
return False
invoice = proposal['invoice']
if invoice not in self.records:
self.trace.append('blocked: unknown invoice')
return False
self.records[invoice]['reference'] = proposal['reference']
self.revision += 1
verified = self.records[invoice]['reference'] == proposal['reference']
self.trace.append('verified save: ' + invoice)
return verified
def main():
app = InvoiceApp()
observation = app.observe('42')
proposal = {'revision': observation['revision'], 'invoice': '42',
'reference': 'REVIEWED'}
print('first save:', app.save(proposal))
print('stale retry:', app.save(proposal))
print('invoice 42:', app.records['42']['reference'])
print('invoice 99:', app.records['99']['reference'])
for event in app.trace:
print(event)
if __name__ == '__main__':
main()
Push it further
Add visual fixtures with resized screenshots and measure target selection, coordinate conversion, and final task success as separate outcomes.