feat: sync latest ARR implementation

This commit is contained in:
Wyndham ARR
2026-07-31 15:11:42 +08:00
parent d6f8a747fa
commit bf7939dd1a
185 changed files with 17527 additions and 2260 deletions

View File

@@ -0,0 +1,35 @@
# Probe Stream Semantics Before Designing Trace Capture
## Trigger
The user pointed to SuperAgent's
`/messages/stream?include_trace=true` capability after the first task-log
implementation reconstructed only ARR database facts. The URL alone did not
establish whether it could replay an existing run or only create a new one.
## Evidence
- `OPTIONS`, `HEAD` and `GET` returned `405 Allow: POST`.
- A no-business-data probe showed the first SSE event was `run.started`, followed
by task/step updates and a terminal run event/end marker.
- Repeating the exact same message and idempotency key created a different
`run_id`; the endpoint did not replay or deduplicate the prior run.
## Lesson
Do not infer read/replay semantics from an observability query parameter. Before
wiring trace capture, verify the HTTP method, event order, connection lifetime
and duplicate-submission behavior with an isolated harmless request. If trace is
emitted only while creating the run, return the handle from the first start event
and keep consuming that same connection; never POST again merely to recover
diagnostics.
## Reusable Check
1. Probe non-mutating methods first and inspect `Allow`/Content-Type.
2. Use a separate no-PII session for the smallest authorized POST probe.
3. Record only schema/event names until the privacy boundary is known.
4. Test identical idempotency keys explicitly; do not assume endpoint parity.
5. Treat an uncertain post-send failure as ambiguous when the server cannot
prove deduplication.

View File

@@ -0,0 +1,44 @@
# Reflection: Verify Runtime Target and Entrypoint Before E2E
## Trigger
Debugging initially followed the obsolete local MCP/ngrok path even after the user had moved services to a server environment. A subsequent SuperAgent export was also a manual chat-upload processor test rather than the accepted ARR Web upload flow.
## Expected Behavior
Before changing credentials or diagnosing transport, identify the exact MCP URL currently saved in SuperAgent and verify that the probe targets that runtime. Before calling a run “end to end,” require an ARR-created `job_id`, attempt identity, OSS provenance, submission grant, MCP receipt, and database evidence.
## Actual Behavior
The local temporary gateway was authenticated successfully but was irrelevant to the server deployment. The manual Agent run processed XML and presented files without `fetch_oss_file` or `arr_submit_processing_result`, so it could never prove the database path.
## Root Cause
- Stale runtime assumption
- Test-mode confusion
- Acceptance gate applied too late
## Evidence
- User correction that the active MCP is server-side rather than the temporary local tunnel
- `.project-docs/50-evidence/topics/2026-07-29-superagent-manual-xml-run-bypassed-mcp.md`
- `deploy/README.md`
## Lesson
Use a two-part preflight for every external E2E:
1. Record the exact configured endpoint and confirm the probe reaches that endpoint.
2. Classify the test entry as manual processor validation or ARR program-triggered ingestion before interpreting any Agent status.
Never synchronize credentials or restart a runtime until both checks identify it as the active target.
## Action
- Preserve the exported-run evidence and current blocker.
- Require server Web upload plus authoritative MCP/database signals for the next acceptance attempt.
## Promotion
Promoted to current-state risks and the evidence index. No architecture decision changes.

View File

@@ -0,0 +1,38 @@
# Reflection: Backend Automation Must Reconcile The Open UI
## Trigger
The worker published monthly reports automatically, but the open page still required a person to click “刷新” before
the new version appeared.
## Expected Behavior
An automated business workflow includes both durable backend completion and automatic reconciliation of the visible
user interface. Once publication is committed, an open list should discover it without another user action.
## Actual Behavior
The page loaded monthly versions only at boot or from a refresh-button handler. Backend automation was complete, but
the UI held a stale snapshot indefinitely.
## Root Cause
- Backend completion and frontend observability were treated as separate acceptance concerns.
- The asynchronous worker cannot return its result through the original upload HTTP response.
- No polling, push channel or visibility-resume contract existed for the monthly list.
## Lesson
For asynchronous publication, acceptance must cover how an already-open client observes the committed result. Prefer a
bounded, visibility-aware synchronization mechanism that avoids overlapping requests and preserves the last good state.
## Action
- Poll only while the monthly tab/document is visible and reload immediately when it becomes active.
- Keep the last good rows on transient background errors and retry automatically.
- Remove the manual refresh control from the primary workflow.
- Verify both rendered state and actual repeated API requests.
## Promotion
Promoted to ADR-001, success criteria, business rules, architecture data flow and the Web static contract tests.

View File

@@ -0,0 +1,54 @@
# Reflection: Coordinate Hot Static Assets With The Long-Lived Backend
## Trigger
The active port-8766 Python process predated the application-login routes, but it reads HTML/CSS/JavaScript from the
workspace on every request. Editing logout/login frontend assets therefore created a temporary new-frontend / old-backend
combination before any intentional process restart.
## Expected Behavior
A route-contract change should activate as one compatible release: the frontend should not advertise a control whose
backend endpoint is absent, and a fail-closed backend should not be restarted until required credentials exist.
## Actual Behavior
The long-lived process continued issuing anonymous CSRF sessions without `username` and returned 404 for `/login`,
while newer static files were immediately visible from disk. Restarting it without credentials would have taken the
whole portal offline.
## Root Cause
- Static assets and Python route code had different activation lifecycles.
- The current workstation process is manually coordinated rather than deployed as one immutable image/restart.
- Login correctly fails startup closed, so activation depends on an operator-owned secret choice.
## Evidence
- Files: `arr_web/app.py`, `arr_web/static/app.js`, `arr_web/static/h5.js`
- Runtime: PID 37865 on port 8766
- Evidence: `50-evidence/topics/2026-07-30-web-login-runtime-mismatch.md`
- Verification: old `/api/session` shape lacks `username`; old `/login` returns 404; isolated new runtime passes login/logout.
## Lesson
Treat hot-read static files plus a long-lived backend as a rolling mixed-version deployment. Before editing, inspect the
active route/session contract. Make new controls feature-detect the new response shape and stay hidden on the old one;
then restart once only after every fail-closed runtime input is ready.
## Action
- Logout controls start hidden and are revealed only when `/api/session` returns an authenticated `username`.
- Keep an old process running until every fail-closed secret exists; if it has already exited, restore only after the
complete previous non-secret runtime composition is also recovered.
- Store the Web password and OSS credentials in Keychain. The user-local launcher contains only allowlisted route
parsing, paths and Keychain labels; it never commits or prints values.
- A launchd-owned process cannot read this Desktop-hosted runtime under the current macOS privacy boundary. The active
local workaround is a desktop-authorized detached Screen session; production should use an approved supervisor and
non-Desktop deployment path.
- Record the exact coordinated restart and acceptance sequence in current state, evidence, stale items and commitments.
## Promotion
Promoted to the frontend compatibility contract, current-state restart gate, login-runtime evidence and this reusable
reflection. No broader ADR is required.

View File

@@ -0,0 +1,46 @@
# Reflection: Current projections must exclude fixtures
## Trigger
Real daily uploads and automatic monthly publication were enabled while the database acceptance fixture remained in
`finance.current_daily_versions`, causing correct aggregation of non-business test data.
## Expected Behavior
The transition from schema acceptance to business-facing use should retire all fixture pins and verify that every
current Finance source has operational provenance.
## Actual Behavior
The fixture's immutable version and current pointer were both retained. Later features validated formulas, lineage,
downloads and max-ARRIVAL consistency against a structurally valid but contaminated snapshot.
## Root Cause
- Weak gate
- Unclear ownership
The handoff documented synthetic-data cleanup as a production gate, but no executable readiness check owned it.
## Evidence
- Current version 2: run `mvp-v1-fixture-20260727`, `synthetic.xml`, provider `local_fixture`.
- [Channel BI contamination evidence](../../50-evidence/topics/2026-07-30-channel-bi-post-update-data-contamination.md)
- `DATABASE_ARCHITECTURE_REASSESSMENT_V2.md` already required synthetic cleanup before production.
## Lesson
Structural reconciliation proves that downstream outputs match current facts; it does not prove those facts are
operational. Before business-facing acceptance, assert provenance as well as counts, hashes and formulas.
## Action
- Add check/eval
- Update gate
Future deployment/readiness work should fail when a current Finance version uses `local_fixture` or another explicitly
non-operational source. Cleanup must preserve immutable history while removing the fixture from the current projection.
## Promotion
Promote this to a deployment/data-readiness gate and automated acceptance check when remediation is implemented.

View File

@@ -0,0 +1,45 @@
# Reflection: Derive Report Watermarks From Business Facts
## Trigger
The user corrected the proposed monthly cutoff source: the Opera XML filename has no date, and the monthly “更新至”
must come from the table's `ARRIVAL` field.
## Expected Behavior
Identify the authoritative business field before deriving a report period or label. Use the committed facts actually
included in the report, not transport metadata, upload names, request time or a nearby technical date.
## Actual Behavior
Earlier planning left the cutoff derivation policy open and existing code accepted a request cutoff, which allowed a
7.30 filename even though the maximum included `ARRIVAL` was 7.27.
## Root Cause
- Source identity was conflated with business time.
- An internal request field was trusted without reconciling it to the generated dataset.
- The output label was validated structurally but not against the report's semantic maximum date.
## Evidence
- User correction on 2026-07-30.
- The pre-fix manual workbook was named “更新至7.30” while included rows ended at `ARRIVAL=2026-07-27`.
- The repaired live report stores `as_of_date=2026-07-27` and core validation enforces equality with max included
`ARRIVAL`.
## Lesson
For derived period labels, trace the value to the authoritative business column and assert it again against the final
dataset. Filenames and wall-clock timestamps are provenance/audit data, not business watermarks unless the domain
explicitly says otherwise.
## Action
- Encode max-included-`ARRIVAL` in ADR-001 and durable business rules.
- Derive worker scope through `daily_version_id` lookups rather than payload/filename dates.
- Reject any non-empty monthly report whose stored `as_of_date` differs from its maximum included `ARRIVAL`.
## Promotion
Promoted to ADR-001, the data flow, business rules, migration column comment and monthly core/worker tests.

View File

@@ -0,0 +1,45 @@
# Reflection: Distinguish a database snapshot from batch completeness
## Trigger
The first Channel BI diagnosis treated the three real versions visible at 15:44 as the complete intended input set and
declared 307 the clean expected total. The user's 07-23 upload committed later at 16:12 and raised the real total to 416.
## Expected Behavior
A live-update diagnosis should timestamp its snapshot, enumerate expected source files/dates, check recent or in-flight
runs, and distinguish “currently persisted” from “business batch complete” before declaring an expected total.
## Actual Behavior
The diagnosis correctly found the one-row fixture but incorrectly promoted the then-current 307-row database subtotal
to the final business expectation. The user's correction was required to reopen the missing-date audit.
## Root Cause
- Weak gate
- Other: temporal incompleteness was mistaken for data correctness
## Evidence
- 15:44 snapshot: three real current versions totaling 307 plus one fixture.
- 16:12:27: daily version 7 committed 109 retained rooms for 07-23.
- Final real total: 416; live source total with fixture: 417.
- [Channel BI contamination evidence](../../50-evidence/topics/2026-07-30-channel-bi-post-update-data-contamination.md)
## Lesson
PostgreSQL is authoritative for what is committed at a given instant, but it does not by itself prove that every
expected source has arrived. Live batch diagnoses need both state reconciliation and completeness reconciliation.
## Action
- Update gate
- Add check/eval
Before declaring a clean expected total after uploads, list expected dates, query recent runs, state the snapshot time,
and wait for or explicitly exclude any missing/in-flight input.
## Promotion
Promote this to the data-diagnosis checklist and future automated batch-completeness checks.

View File

@@ -0,0 +1,45 @@
# Keep Deterministic Results Machine-to-Machine
## Trigger
The fixed processor produced a complete valid 135-record result, but the model-mediated MCP call submitted only 20
records. Prompt strengthening improved tool selection and fetch behavior but could not guarantee lossless serialization
of a large structured payload.
## Expected Behavior
Once deterministic code has created a schema-valid result, the receiving system should validate and ingest that exact
machine artifact without asking a model to reconstruct the payload as tool arguments.
## Actual Behavior
The result crossed an unnecessary model serialization boundary. That boundary introduced truncation, rereads and
retry ambiguity even though both the source fetch and deterministic business processing had already succeeded.
## Root Cause
- Unclear ownership of structured-result transport
- A probabilistic orchestration boundary was placed between deterministic producer and deterministic consumer
## Evidence
- `.project-docs/50-evidence/topics/2026-07-30-superagent-fetch-oss-prompt-experiment.md`
- `.project-docs/50-evidence/topics/2026-07-30-arr2-programmatic-pipeline.md`
- `arr_web/programmatic.py`
- `tests/test_arr_programmatic.py`
## Lesson
Use models to interpret ambiguous inputs or choose work when that is genuinely required. Do not use a model as the
transport encoder for a complete, machine-generated business result. Preserve the original artifact, validate it at the
system boundary, and make the database commit authoritative.
## Action
- Updated the architecture through ADR-004.
- Added programmatic success/failure vertical slices and active-runtime deployment guards.
## Promotion
Promoted to ADR-004, the ARR2.0 architecture documents, deployment contracts and regression tests. No new skill is
needed unless this pattern recurs in another project.

View File

@@ -0,0 +1,42 @@
# Reflection: Formatting is not business state
## Trigger
An early Booking parser interpretation treated a yellow source row as cancellation. The supplied real workbook showed
that a fully yellow row can still be the authoritative active Tour Code row, and the user confirmed that only explicit
source cancellation text should cancel it.
## Expected Behavior
The parser should derive replacement/cancellation from explicit business content and documented row order, not from
presentation-only cell formatting.
## Actual Behavior
A visual formatting heuristic could have removed a valid final Tour Code allocation.
## Root Cause
- Weak gate: a spreadsheet style was promoted to business meaning without an explicit contract or counterexample test.
## Evidence
- Files: `booking_ingestion/excel.py`, `tests/test_booking_excel_ingestion.py`
- Command output: the supplied workbook retains its yellow final row; the regression test
`test_yellow_formatting_alone_does_not_cancel_a_tour` passes.
- Docs involved: `.project-docs/40-domain/business-rules.md`
## Lesson
Spreadsheet color, font, border and other presentation metadata must remain non-authoritative unless the user explicitly
defines that formatting as a business field. When row state matters, prefer text/column contracts and add a real-style
counterexample before accepting the rule.
## Action
- Add check/eval: retain a yellow-row regression fixture and keep cancellation text-based.
- Update docs: promote the rule to durable Booking business rules.
## Promotion
Business rule plus parser regression test.