Exercises: Descriptor Evidence Studio¶
Page Maps¶
flowchart LR
protocol["Protocol inventory"] --> precedence["Lookup prediction"]
precedence --> binding["Binding identities"]
binding --> storage["Quantity storage"]
storage --> capstone["Capstone field ownership"]
capstone --> review["Design review"]
This studio uses the shipped Module 07 lab and the incident-plugin capstone. Do not create unrelated toy descriptors unless an exercise explicitly asks for a minimal counterexample.
Start from:
Keep the JSON output available while you work.
Every exercise uses the same evidence cycle:
flowchart LR
question["Name one lookup question"] --> static["Inspect the attached object"]
static --> predict["Predict owner and winning layer"]
predict --> run["Run one deliberate operation"]
run --> compare["Compare prediction with evidence"]
compare --> limit["Record the proof limit"]
Submission packet¶
For each exercise record:
| Field | Required evidence |
|---|---|
| owner | class, descriptor, instance, wrapper, or metaclass |
| timing | class creation, class access, instance read, instance write, or call |
| static evidence | value retrieved without triggering the behavior |
| predicted result | winning hook or lookup layer |
| observed result | output, instance dictionary, identity, or failure |
| preserved contract | earlier behavior that must remain true |
| limitation | what the evidence does not prove |
Exercise 1: Separate naming from descriptor status¶
Starting context:
NameAwaredefines only__set_name__StoredFielddefines__get__,__set__, and__set_name__
Objective:
Produce a protocol inventory for both objects without using their class names as evidence.
Constraints:
- inspect hooks on
type(value) - retrieve each installed object with
vars(owner) - do not call an instance attribute during classification
Expected evidence:
- both recorded installation names
- one
not-a-descriptorclassification - one
dataclassification - a sentence explaining why
__set_name__belongs to a different time
Acceptance check:
Preserve:
- class access to
StoredFieldreturns the descriptor itself
Exercise 2: Predict lookup before reading¶
Starting context:
Use precedence_evidence() and explain_lookup().
Objective:
Add a fourth name to the local Delivery example: a non-data descriptor with no
same-named instance entry. Predict all four winners before performing reads.
Constraints:
- use
inspect.getattr_staticthrough the shipped helper - distinguish the public shadow name from a private storage name
- keep
ordinary_lookup_onlyexplicit
Expected evidence:
- four
LookupDecisionrecords - four actual reads
- one intentional data-descriptor conflict in
vars(instance) - one intentional non-data shadow
Acceptance checks:
- every prediction matches the actual result
- removing the non-data shadow changes only that one winner
Preserve:
- the data descriptor continues to read its private storage value
Exercise 3: Audit binding without invoking the action¶
Starting context:
The capstone stores a wrapped deliver function on ConsoleNotifier.
Objective:
Inspect the transition from static wrapper function to bound method.
Constraints:
- retrieve the static value with
inspect.getattr_static - construct a plugin only if needed for binding; do not invoke
deliver - compare with the Module 07
MethodBindingfields
Expected evidence:
- static value type
- descriptor category
- bound value type
bound.__func__ is static_valuebound.__self__ is plugin- a note separating wrapper ownership from binding ownership
Acceptance check:
- action history remains empty
Preserve:
- the visible action signature remains unchanged
Exercise 4: Extend the quantity field honestly¶
Starting context:
Quantity accepts seconds and milliseconds and stores canonical seconds.
Objective:
Create a timeout field that also accepts minutes and has a maximum of five minutes.
Constraints:
- keep seconds canonical
- add
"min": 60.0 - do not add string parsing
- reject
bool, non-finite values, and values above 300 seconds - use two instances
Expected evidence:
timeout = (2, "min")stores120.0timeout.in_unit("min")returns2.0(6, "min")fails against the canonical maximum- two owner dictionaries remain independent
Acceptance check:
Add focused tests rather than changing the stable lab packet.
Preserve:
- all existing descriptor lab tests pass
Exercise 5: Compare capstone field schema with ownership¶
Starting context:
Run:
Objective:
Explain why these commands are complementary rather than duplicates.
Constraints:
- do not construct or invoke a plugin
- identify which output is public schema and which is implementation ownership evidence
- trace
WebhookNotifier.endpoint
Expected evidence:
StringFieldas the static descriptor typedataas its categoryWebhookNotifieras the declaring class_endpointandplugin-instance.__dict__as the storage boundaryconstructed: falseandexecuted: false
Acceptance checks:
and the focused capstone field and CLI tests.
Preserve:
- the existing
fieldcommand retains its schema-focused output
Exercise 6: Write the ownership review¶
Review these requirements:
- one class computes a display label
- many plugin classes reuse bounded integer configuration
- all assignments fail after initialization
- duplicate field names fail during class-body execution
- one method performs delivery I/O
Objective:
Choose the narrowest honest owner for each requirement.
Constraints:
- choose among property, descriptor,
__setattr__, metaclass namespace, and method - reject one lower or higher power where a realistic alternative exists
- price maintenance cost
Expected evidence:
| Requirement | Chosen owner | Rejected owner | Deciding pressure |
|---|---|---|---|
Acceptance checks:
- every chosen owner matches the timing it needs
- no descriptor owns whole-object or class-family policy
- no property is rejected merely because descriptors are “more reusable”
- the I/O operation remains explicit
Preserve:
- Module 06's lower-power ladder remains the starting point
Final studio proof¶
Run focused verification:
Then submit:
- the six exercise records
- any focused tests you added
- one paragraph connecting
Quantityto the capstoneField - one remaining limitation that neither descriptor solves
Self-review before answers¶
Do not open the answers until you can state:
- why
__set_name__is insufficient for descriptor status - why the same instance dictionary entry wins in one case and loses in another
- what
__func__and__self__prove - where both quantity and capstone values live
- why metaclass collection does not make the metaclass the field-access owner
Continue through Module 07¶
- Previous: Worked Example
- Next: Exercise Answers