Bring SCHEDULE_DESIGN_zh.md to the same reference-implementation
walkthrough shape as FEEDBACK_DESIGN_zh.md: it now assumes the spec has
been read, drops the mid-migration 'current state' warnings (the legacy
code is deleted), and covers what the old version predated -- the
commands chapter (UNSET three-state updates, ContextChange, why the
clock- and callback-driven writes stay plain methods), the adapters and
composition-root chapter (CAS field ownership, the corrupt-row error
split, the two anti-corruption layers and the inbound completion
listener), the dispatch journey with the three-driver macro diagram the
spec's §5.3 points at, and the test-layering table for the current
suites.
The spec's §6 marks the schedule slice done and drops the three
completed to-dos; the docs index gains the schedule walkthrough next to
its sibling.
- HEXAGONAL_ARCHITECTURE_zh.md becomes the spec: Cockburn/AWS-sourced
standard structure (domain seven-piece layout, file naming rules),
the four-transformation conversion chain with fixed owners and method
names, commands/events design with upgrade triggers, an enforced rule
table, and generic read/write sequence + class diagrams
- FEEDBACK_DESIGN_zh.md is rewritten as the reference-implementation
walkthrough of that spec (commands, exceptions split, _apply mapping,
composition root, updated test map and pitfalls)
- add the definition and dispatch diagrams under docs/assets
HEXAGONAL_ARCHITECTURE_zh.md now carries rules only: the two orthogonal
boundaries, the AWS three-folder mapping, the two kinds of secondary
adapter, and how the boundaries are mechanically enforced. The feedback
walkthrough, its known gaps, and its todo list move to a module document,
so the guide stays readable as more modules are migrated.
Two corrections to the guide, both of which would have misled a reader:
- Ports belong inside `domain/`, not beside it. AWS places `ports/` as a
subdirectory of `domain/` and describes the domain folder as "domain and
interfaces"; lifting ports into a third top-level layer would make the
domain depend on an outside package to declare its own needs. The guide
now states this explicitly, since the opposite reading is common.
- The walkthrough had the service calling RunLookup before building the
aggregate. The code does the reverse, and the order matters: validation
runs before any port call, so an invalid rating on a nonexistent run is
reported as InvalidRatingError rather than RunNotFoundError. The same
section also called that check authorization; it is referential
integrity, and authorization is the router's owner_check plus this check
taken together -- which is why the port takes no user_id.
FEEDBACK_DESIGN_zh.md is new and follows the SCHEDULE_DESIGN_zh.md shape:
the aggregate and its invariants, both ports and the conventions that
matter more than their signatures, the four use cases, both adapters, the
walkthrough, the test layering, an extension guide, and a pitfall list.
Three things it records that were not written down anywhere:
- The aggregate reads the system clock in its default factory, which
schedule deliberately avoids. Acceptable while the timestamp is only a
bookkeeping stamp and feeds no rule; noted with the condition that would
force a change.
- A repository that explicitly inherits its Protocol turns a misspelled
method into a silent None, because the inherited body is `...`. Hit for
real during the move. isinstance() cannot detect it, so asserting "the
port is satisfied" is not a substitute for asserting return values.
- RunLookup has no contract test against a real RunStore. A renamed key in
the dict RunStore.get() returns would turn every rating into a 404 with
the suite still green.
README.md indexes both under Quick Links, next to ARCHITECTURE.md.