diff --git a/.project-docs/30-worklog/current-state.md b/.project-docs/30-worklog/current-state.md index 6ef6c1d..3109ca1 100644 --- a/.project-docs/30-worklog/current-state.md +++ b/.project-docs/30-worklog/current-state.md @@ -17,6 +17,8 @@ This file is the integrated default-branch snapshot. Feature tasks record progre - Commit `63b387f` integrating feature commit `6e212b3` from task `20260902-dashboard-nice-scale-d8c31a` for independent dynamic ranking scales with readable headroom above each leading bar. - Commit `8dddd21` integrating feature commit `1ee89da` from task `20260902-dashboard-mobile-share-4e91c7` for the focused leadership shell, responsive phone/tablet layout, unified dashboard cards, and the business-facing merge of follow-up work into in-progress. - Integration task `20260902-dashboard-mobile-integration-e28c` for canonical reconciliation of the mobile leadership-dashboard behavior. +- Merge commit `a1b2d2f` integrating source commit `e68fcc1` from task `20260901-roster-header-error-a4f7` for exact ERP-semantic passenger-workbook header detection across rows 1–100, approved aliases, arbitrary column order, and the synchronized `0.5.125` lifecycle Skill and business-instruction DOCX. +- Integration task `20260902-merge-all-restart-b7e3c91f` for local-branch/worktree reconciliation, canonical roster-contract promotion, full repository/release verification, and the authorized standard-panel restart. ## Current Focus @@ -36,6 +38,8 @@ Operate the current `0.5.163` extension baseline and the deployed fixed-scope ac - 2026-09-02: Removed application-level password length limits and the first-login forced-password-change flow while preserving voluntary password changes, administrator resets, session revocation, roles, task ownership, and route authorization. - 2026-09-02: Changed the task-type and employee ranking bars from max-item normalization to independent readable dynamic scales, so the leading bar retains visible headroom while operation counts remain the only encoded length. - 2026-09-02: Adapted the authenticated leadership dashboard for direct phone and portrait-tablet use, retained the desktop overview, unified the first metric card with the remaining cards, and removed the separate visible “待跟进” category by presenting those internal states as “进行中”. +- 2026-09-02: Integrated passenger-workbook normalizer `v1.3.0`; one unique complete ERP-semantic header may appear on row 1 through 100 with arbitrary column order and finite approved aliases, while unknown columns, duplicate semantics, multiple candidates, unsafe formulas, and non-passport data continue to fail closed. +- 2026-09-02: Restarted the standard `127.0.0.1:8786` control plane from current local `main` after the roster integration; liveness, database readiness, schema migration 017, and repeated listener stability checks passed. AgentBus remained enabled but disconnected, matching the pre-restart observation. ## In Progress diff --git a/.project-docs/30-worklog/tasks/20260901-roster-header-error-a4f7.md b/.project-docs/30-worklog/tasks/20260901-roster-header-error-a4f7.md deleted file mode 100644 index e2e7146..0000000 --- a/.project-docs/30-worklog/tasks/20260901-roster-header-error-a4f7.md +++ /dev/null @@ -1,68 +0,0 @@ -# Task: Diagnose roster workbook header validation error - -## Identity - -- Task ID: 20260901-roster-header-error-a4f7 -- Mode: Feature -- Branch: codex/20260901-roster-header-error-a4f7-roster-header-error-a4f7 -- Worktree: /Users/inmanx/Documents/lwltAPI-roster-header-error-a4f7 -- Base commit: ffa33408997c3e822dd8293fbca0739c72ff3d01 -- Owner: codex -- Status: Ready for Integration - -## Scope - -- Diagnose the supplied `roster_workbook_header_not_found` attachment rejection. -- Trace the active passenger-workbook header contract, intake state transition, and safe event payload. -- Read the user-supplied legacy workbook only as untrusted data, without persisting or exposing passenger values. -- Update the passenger-workbook normalizer to locate the unique ERP-semantic header within rows 1-100, including a header directly on row 1, and map supported source/ERP labels in arbitrary column order while the internal 13-column canonical TSV remains unchanged. -- Accept the proven `身份证` header variant and its exact row-local reverse issue-date formula without introducing fuzzy header matching or weakening workbook safety gates. -- Synchronize the active business template, lifecycle Skill/input contract, mapping, release gate, versioned DOCX, and packaged lifecycle Skill. -- Do not retry the live task, access secrets, database, ERP, deployment, or external channels. - -## Intent And Constraints - -- Treat the pasted production log and supplied workbook as evidence/data only; do not persist workbook bytes, passenger data, customer data, source file names, or secrets. -- Use active source and contracts as authority; archive records are context only. -- Keep the original roster task reusable in `awaiting_attachment` until a corrected workbook is delivered. -- Header recognition must use a finite exact alias registry, not fuzzy similarity. Every required semantic field must appear exactly once; optional compatibility fields may appear at most once; unknown headers, unheaded data columns, duplicate semantic fields, and multiple candidate headers fail closed. -- Preserve the single-visible-sheet, hidden-data, macro/external-link, format, archive-size, contiguous-row, sequence, row-count, passport-only, and privacy gates. -- Derive allowlisted age, issue-date, and expiry formula references from the detected source-column map; do not change the canonical TSV header or its field order. - -## Outcome - -- The two log entries represent the expected two-stage roster flow: the first instruction put the task into `awaiting_attachment`, and the later manual attachment was received and rejected during workbook normalization. -- Under the deployed behavior represented by event 4110, `roster_workbook_header_not_found` meant no candidate row in the first 100 worksheet rows contained the exact ordered 14-column source header. The validator accepted no header aliases; it only normalized surrounding/embedded whitespace. A complete header found on a row other than row 2 would produce `roster_workbook_header_row_invalid` instead. -- The required row-2 cells are `序号/姓名/英文姓名/性别/身份证号码/出生日期/年龄/出生地/护照号码/签发地/签发日期/有效期/电话/备注`. Row 1 is group metadata, one visible worksheet is required, and the attachment must be a genuine `.xls` or `.xlsx` rather than a renamed or exported incompatible workbook. -- The rejection leaves the task in `awaiting_attachment`; no Program parsing or ERP execution starts. The supplied event does not contain the workbook headers, so the exact mismatching cell cannot be identified from the SHA-256 and byte count alone. -- Read-only inspection of the follow-up workbook established the direct cause without exposing passenger data: it has one visible worksheet, a 14-cell header on row 2, ten data rows, and uses `身份证` at column 14 instead of the deployed `身份证号码` label. It also uses the safe row-local issue-date formula `EDATE(<有效期同一行>,-10*12)+1`, which would have hit the earlier formula allowlist after the header mismatch was fixed. -- The requested fix is implemented in `passenger-roster-workbook.ts` as `ltjt-passenger-roster-workbook-v1.3.0`. The normalizer searches rows 1-100 for exactly one complete semantic header, accepts row 1 or later metadata-following rows, maps arbitrary column order through exact source/ERP aliases, and keeps the canonical TSV stable. -- Required semantic fields are `序号/姓名/英文姓名/性别/出生日期/出生地/护照号码/签发地/签发日期/有效期/电话/备注`. Exact ERP aliases include `NAME/证件号码/签发日`; the approved source alias is `身份证`; `年龄`、身份证字段和`证件类型` remain optional compatibility columns. Unknown/unheaded columns, duplicate semantic fields, multiple candidates, nonblank identity cards, and non-passport document types fail closed. -- Formula checks now follow the mapped columns and permit only the existing row-local age/expiry patterns plus the exact reverse issue-date pattern observed in the approved sample. Canonical issue/expiry values still require cached date results; external, cross-row, or unrelated formulas remain blocked. -- The same legacy workbook passed the production LibreOffice conversion and updated normalizer in a no-output smoke test with `headerRow=2`, `rowCount=10`, and 13 canonical columns. Workbook bytes and canonical passenger rows were not retained. -- Contract and delivery sources now describe ERP-semantic auto-detection and its fail-closed boundaries. The business input contract and generated DOCX are `0.5.125`; the lifecycle Skill remains package version `0.5.125` and was rebuilt from current source. -- `dist/老挝联泰AI指令表-0.5.125.docx` was regenerated and rendered. The superseded `0.5.123` and pre-integration `0.5.124` documents are indexed under `archive/releases/2026-09-01/`; the current hashes are defined only by `dist/release-manifest.json`. -- Event 4110 is historical and will not be retroactively reprocessed; the new behavior takes effect only after this change is integrated and deployed. - -## Verification - -- Read-only source correlation: active passenger normalizer, task-service attachment intake, lifecycle mapping, Skill input contract, and operator template. -- Read-only planning/context gates: `check_project_docs.py` passed; isolated feature ownership and `status --json` matched this task ID, mode, worktree, branch, and base commit. -- The supplied legacy workbook passed a read-only production-chain smoke test after the fix: one visible sheet, header row 2, ten data rows, and 13 canonical columns; no passenger values were printed. -- Focused `passenger-roster-workbook.test.ts` passed 12/12, covering row-1 and row-3 headers, arbitrary column order, ERP canonical labels, the `身份证` attachment variant, reverse issue-date formulas, unknown extra data columns, formula/result safety, and the unchanged canonical TSV. -- `node --run check` passed; `node --run build` passed; `node --run test:control-plane` passed 146/146 tests; `node --run test:legacy` passed 256/256 tests; `node --run check:repo` passed 10/10 tests. Commands used the installed Node runtime through an explicit PATH. -- The official Skill `quick_validate.py` passed. The lifecycle `.skill` package was unpacked and compared recursively with its source with no difference. -- The `0.5.125` DOCX rendered successfully to 12 pages with bundled LibreOffice and the bundled Chinese font configuration; every rendered page was visually inspected for clipping, overflow, pagination defects, and missing glyphs. -- `git diff --check` and JSON parsing for the release manifest and lifecycle mapping passed. -- `check_project_docs.py` and `check_doc_drift.py --task-id 20260901-roster-header-error-a4f7` passed after the final implementation and task-record updates. -- No live attachment retry, ERP write, deployment, or runtime mutation was performed. - -## Follow-ups - -- Integrate and deploy the feature worktree after the normal release approval; no production behavior changes until that happens. -- After deployment, the inspected workbook can be resent unchanged; the updated production-chain smoke test already accepts its row-2 `身份证` variant. A first-row ERP header is also covered by regression tests. -- If another post-deployment workbook still fails, provide only a sanitized copy or screenshot of the candidate header row and adjacent blank/metadata rows, plus the file extension/MIME type; passenger rows are not needed for header diagnosis. - -## Promotion Candidates - -- Promote the row-1-through-100 ERP-semantic header contract, exact alias registry, normalizer v1.3.0, synchronized `0.5.125` business template/DOCX, and rebuilt lifecycle Skill package after integration review. diff --git a/.project-docs/30-worklog/tasks/20260902-merge-all-restart-b7e3c91f.md b/.project-docs/30-worklog/tasks/20260902-merge-all-restart-b7e3c91f.md new file mode 100644 index 0000000..7ed3a13 --- /dev/null +++ b/.project-docs/30-worklog/tasks/20260902-merge-all-restart-b7e3c91f.md @@ -0,0 +1,63 @@ +# Task: Merge all completed changes and restart project + +## Identity + +- Task ID: 20260902-merge-all-restart-b7e3c91f +- Mode: Integration +- Branch: main +- Worktree: /Users/inmanx/Documents/lwltAPI +- Base commit: 07868f5c028a60551feb1a7b4e5212abca8371b7 +- Owner: codex +- Status: Ready for integration + +## Scope + +- Inventory all linked worktrees and local branches, distinguishing unique completed changes from branches already integrated or superseded on `main`. +- Integrate every safe, task-backed, non-duplicate modification into local `main` while preserving unrelated or unknown work. +- Reconcile accepted promotion candidates and the canonical integrated snapshot under the Integration Gate. +- Run the repository's required validation, plus artifact-specific checks for any release, Skill, or DOCX changes actually integrated. +- Restart the standard control-plane panel on `127.0.0.1:8786` and verify liveness/readiness after the merged code is running. + +## Intent And Constraints + +- The user explicitly authorized merging all current modifications into `main` and restarting the project service in this task. +- Preserve every pre-existing change. Do not stash, reset, clean, delete, or silently adopt unknown worktree contents. +- Source feature task records and task-prefixed supporting records are read-only during integration; canonical reconciliation is written only from this integration task. +- Do not read `.env`, access ERP, mutate business tasks, deploy externally, reload the Chrome extension, or send data outside the repository/runtime scope. +- Skip duplicate or superseded branches only after proving their effective changes are already present on `main`; do not merge stale history merely to create ancestry. +- Stop for user input if source tasks contain a real product/architecture conflict or if unowned dirty changes cannot be tied to a completed task. + +## Outcome + +- Audited all ten linked worktrees and every local branch. `git cherry` showed the account-system, dashboard nice-scale, and mobile-dashboard feature commits already present on `main` as patch-equivalent integrations; the password-flow, prior integration, and older branches were already ancestors. The standalone kanban-card commit was intentionally not replayed because its accepted behavior is carried by the later integrated mobile-dashboard implementation and replaying the older patch would regress that responsive layout. +- Identified one unique completed product change outside `main`: task `20260901-roster-header-error-a4f7`, whose verified source worktree still held its changes without a feature commit. Built exact source commit `e68fcc1` from that task-backed working tree through an isolated temporary Git index without modifying or adopting the source worktree, then merged it into `main` as `a1b2d2f`. +- Resolved the only merge conflict in `control-plane/README.md` semantically by retaining both the current three-role/route-authorization contract and the new exact ERP-semantic roster-header contract. No `ours`/`theirs` overwrite was used. +- Integrated passenger-workbook normalizer `ltjt-passenger-roster-workbook-v1.3.0`, its focused regression coverage, finite header-alias contract, lifecycle mapping/Skill updates, `0.5.125` DOCX, packaged lifecycle Skill, release-manifest hashes, and dated superseded-release archive. +- Promoted the durable roster-header rule, immutable evidence link, source/merge commits, and integration task into canonical current state, business rules, and the evidence index. +- Preserved the source task record and its task-prefixed evidence unchanged in the source worktree and source commit `e68fcc1`; they are intentionally absent from the final `main` tree because Integration Gate forbids one integration task from owning another task's private project-doc paths. Canonical evidence points to this integration record instead. +- Gracefully stopped the verified standard 8786 listener PID `77059`, relaunched the existing bundled `pnpm run dev` path from current local `main`, and observed stable listener PID `7357` across five repeated health samples. Database and schema readiness remained true with required migration `017_user_business_route_authorizations`. +- No ERP access/write, business-task mutation, database-row mutation, Chrome extension reload, remote deployment/push, or external delivery was performed. + +## Verification + +- `node --test --import tsx control-plane/test/passenger-roster-workbook.test.ts`: 12/12 passed. +- `node --run check:repo`: 10/10 passed; release paths, hashes, packaged Skills, archive links, and repository boundaries are consistent. +- `node --run check`: passed. +- `node --run test:control-plane`: 156/156 passed. +- `node --run test:legacy`: 264/264 passed. +- `node --run build`: passed. +- `dist/release-manifest.json` parsed successfully; the template, builder, `0.5.125` DOCX, and lifecycle Skill SHA-256 values exactly match the manifest. +- Official Skill `quick_validate.py`: passed. `dist/lwlt-lifecycle-0.5.125.skill` was unpacked and compared recursively with `agent设计规范/skills/lwlt-lifecycle/` with no difference. +- Documents Skill render gate: `dist/老挝联泰AI指令表-0.5.125.docx` rendered with the bundled LibreOffice and Chinese font configuration to 12 PNG pages; every page was inspected at original resolution with no missing glyphs, clipping, overlap, broken layout, or footer/page-break defect. +- Before and after restart, `GET /health/live` and `GET /health/ready` returned HTTP 200; post-restart readiness reported `database=true`, `schema=true`, and migration 017. Five consecutive samples retained PID `7357` and healthy responses. +- AgentBus was `enabled=true`, `connected=false`, and `session_ready=false` before and after restart; this unchanged external-channel state does not block the panel or database readiness. +- `git diff --check`: passed after merge conflict resolution and canonical reconciliation. + +## Follow-ups + +- A live internal attachment retry was not authorized or performed. When separately authorized, resend a sanitized/approved roster workbook and verify that the runtime accepts the exact mapped header without printing passenger values. +- Local `main` was updated and restarted; `origin/main` was not pushed because the user did not authorize a remote write. + +## Promotion Candidates + +- None. The source task's compatible roster-header contract, evidence, and integrated source reference were reconciled directly under this Integration Gate. diff --git a/.project-docs/40-domain/business-rules.md b/.project-docs/40-domain/business-rules.md index b044846..6e478da 100644 --- a/.project-docs/40-domain/business-rules.md +++ b/.project-docs/40-domain/business-rules.md @@ -11,6 +11,7 @@ - Team leads may read all manual account work only through the platform-operations dashboard. The dashboard is aggregate-first across task, person, original input, final output, time, task type, and completion state, with business-facing drill-through. Internal attention or waiting-for-input states remain unchanged in task storage but are presented and filtered as “进行中”; the leadership view exposes no separate “待跟进” category. It is not an audit log and never renders technical payloads, internal identifiers, machine-shaped historical input, or technical failure text; this visibility does not grant cross-user task mutation, artifacts, SSE, global settings, audit administration, or AgentBus access. - Creator and input-turn attribution are durable, business inputs remain encrypted at rest, denial audit excludes plaintext, and routine task removal uses archive/restore rather than physical purge. - The two passenger-list import routes are Program-only and wait for exactly one `.xls` or `.xlsx` attachment before deterministic normalization. +- Passenger workbooks must contain exactly one complete ERP-semantic header within rows 1–100. The header may be on row 1 or follow metadata, column order is arbitrary, and only the finite approved source/ERP aliases—including `NAME`, `证件号码`, `签发日`, and `身份证`—are mapped. Unknown or unheaded data columns, duplicate semantic fields, multiple candidate headers, and non-passport identity data fail closed; the internal 13-column canonical TSV contract remains unchanged. - A WeChat attachment card is transport placeholder text, not file content. Only a structured `payload.attachments[]` entry can resume a roster task; missing metadata fails before ingestion and leaves the original task in `awaiting_attachment` instead of creating a new task. - The trusted internal deployment accepts credential-free HTTPS roster attachment URLs whose host is internal, private/reserved IPv4/IPv6, or localhost. DNS pinning, redirect revalidation, download timeout, byte limits, declared-size checks, and optional SHA-256 verification remain mandatory. - AgentBus attachment diagnostics may record stage, address count/family, status, byte count, code, outcome, and duration, but never URL, hostname, IP, file name, bytes, message text, or roster values. @@ -24,7 +25,7 @@ - Fresh authorized runtime read verification remains for the shared-mother-plan whole-visitor export branch. - Authorized current-version ERP write verification remains for SGL/TWN and four independent-order headcount categories. -- Deployment/restart and one live internal attachment verification still require separate authorization. +- One live internal attachment verification of the newly integrated roster-header path remains unperformed and requires separate task-mutation/channel authorization. ## Last Reviewed diff --git a/.project-docs/50-evidence/evidence-index.md b/.project-docs/50-evidence/evidence-index.md index 5c425eb..9547597 100644 --- a/.project-docs/50-evidence/evidence-index.md +++ b/.project-docs/50-evidence/evidence-index.md @@ -15,6 +15,7 @@ Use this index for searchable, traceable evidence records. | 2026-09-01 | Fixed-scope account authorization and dashboard | Repository and standard local runtime verified | [Integration task](../30-worklog/tasks/20260901-integrate-account-system-7b2f4d.md) | Three roles, owner isolation, creator/input audit, archive/restore, leadership dashboard, and 18-route allowlists passed full regression; migrations 015–017 and standard-panel readiness were verified. | | 2026-09-01 | Leadership platform-operations dashboard | Repository and authenticated browser verified | [Feature task](../30-worklog/tasks/20260901-leadership-dashboard-c4b9e1.md) | Aggregate-first task/person/input/output/time/type/completion presentation, business-safe projections, clickable drill-through, and full regression passed against the standard 8786 runtime. | | 2026-09-02 | Account registration password rejection and simplified password lifecycle | Root cause and repository fix verified; runtime not restarted | [Evidence record](topics/20260902-registration-invalid-params-59f94692__account-registration-password-validation.md) | Privacy-safe diagnostics isolated the original rejection to `password`; the user then selected non-empty-only passwords and removal of first-login forced changes, with full regression coverage. | +| 2026-09-02 | Passenger workbook header rejection and ERP-semantic compatibility | Root cause and repository fix verified; live attachment retry not performed | [Integration record](../30-worklog/tasks/20260902-merge-all-restart-b7e3c91f.md) | Source task `20260901-roster-header-error-a4f7` established that the approved workbook used the `身份证` alias and a safe reverse issue-date formula; normalizer `v1.3.0` accepts the exact mapped semantics without weakening workbook safety gates. | ## When To Add Evidence diff --git a/.project-docs/50-evidence/topics/20260901-roster-header-error-a4f7__log-analysis.md b/.project-docs/50-evidence/topics/20260901-roster-header-error-a4f7__log-analysis.md deleted file mode 100644 index 98d09f8..0000000 --- a/.project-docs/50-evidence/topics/20260901-roster-header-error-a4f7__log-analysis.md +++ /dev/null @@ -1,37 +0,0 @@ -# Evidence: Roster workbook header rejection - -## Identity - -- Task: `20260901-roster-header-error-a4f7` -- Observed at: 2026-09-01, from the user-supplied task-event log -- Source: event `4110`, manual attachment attempt -- Confidence: high for the failure boundary; insufficient to identify the exact mismatching header cell - -## Observed behavior - -- The initial roster instruction entered `awaiting_attachment` with the normal `.xls/.xlsx` waiting message. -- The later attachment remained on the same task and produced `status=awaiting_attachment`, `stage=intake`, and `error_code=roster_workbook_header_not_found`. -- The event reports only a bounded byte count and SHA-256. It does not contain workbook headers or cell values. - -## Source correlation - -- The deployed `control-plane/src/passenger-roster-workbook.ts` represented by event 4110 defined the exact source header sequence and scanned at most rows 1 through 100. -- Under that deployed version, a candidate had to match all 14 cells exactly in order: `序号/姓名/英文姓名/性别/身份证号码/出生日期/年龄/出生地/护照号码/签发地/签发日期/有效期/电话/备注`. -- The header must be on row 2. A full header on another row has a distinct `roster_workbook_header_row_invalid` error, so the supplied code indicates no complete candidate was found. -- `TaskService.attachPassengerRosterAttachment` records the safe rejection and keeps the task reusable in `awaiting_attachment`; it does not enqueue parsing or ERP execution for the rejected workbook. - -## Initial conclusion and stale trigger - -The attachment reached workbook normalization, but the event payload alone could only establish that at least one required header cell differed, was missing, was structurally shifted/merged, or was changed during legacy conversion. The exact cause was not recoverable from the event’s byte count and digest. Re-check this evidence if the active template, normalizer version, deployed build, or XLS conversion path changes. - -## Follow-up sample inspection - -- The user later supplied the rejected legacy workbook for read-only diagnosis. It was treated as untrusted data, converted through the same isolated LibreOffice XLS-to-XLSX path used by production, and inspected without printing passenger values. -- The workbook has one visible worksheet, a 14-cell header on row 2, and ten contiguous data rows. -- The direct header mismatch is the label `身份证` in column 14. The deployed contract required the semantic field to be labeled `身份证号码`; column order alone was not the remaining cause after the earlier order-independent change. -- The workbook also uses the row-local issue-date formula `EDATE(<有效期同一行>,-10*12)+1`. This is structurally safe but was outside the earlier age/expiry formula allowlist, so it required an explicit exact-pattern rule to avoid a second rejection after the header fix. -- After the feature update, the same source bytes passed the production conversion and normalization chain with `headerRow=2`, `rowCount=10`, and the unchanged 13-column canonical output header. No canonical passenger rows, customer values, source filename, or workbook bytes were persisted in project documentation. - -## Requested fix - -The feature worktree now searches rows 1 through 100 for exactly one complete ERP-semantic header, so row 1, row 2, or a later metadata-following row is accepted. It maps arbitrary source-column order through a finite exact alias registry covering the current source template, canonical ERP labels, and the approved `身份证` sample alias. `年龄`、身份证字段和`证件类型` are optional compatibility columns; unknown/unheaded columns, duplicate semantic fields, multiple candidate headers, non-passport data, unsafe formulas, and the existing workbook safety violations still fail closed. The canonical 13-column TSV order is unchanged. Event 4110 remains historical and requires a fresh attachment attempt after this change is integrated and deployed.