Repository navigation
feat(cmdb-import): read the archive sheet and let module and usage be archived - #1285
WilcoLouwerse wants to merge 7 commits into
Conversation
… archived Adds the OpenSpec change cmdb-import-archive-reconciliation (REQ-CMDB-015..017, REQ-CMDB-012 and REQ-CMDB-014 modified). The register fragment opts module (0.3.9) and usage (1.5.7) into OpenRegister's archive state, the import profile names the sheet "Gearchiveerde Applicaties" and the accepted missingRecords modes, and the workbook reader returns the APPIDs of that sheet, read under the same bounds as the CMDB sheets for its key column only. The archived-applications fixture covers it. First of three slices of #1281; nothing reads the archive sheet yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Quality Report — ConductionNL/stackiq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue-demi | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 133/133 | |||
| npm | ✅ | ✅ 807/807 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| lockfile sync | ✅ | ||||
| PHPUnit | ✅ 1233/1233 · 20 skipped | ||||
| Newman | ⏭️ | ||||
| Playwright | ⏭️ deferred: E2E runs locally and on the promotion path only. This pull request targets development, so the suite is asked once per promotion into beta and main rather than once per push per open pull request. Run it locally with npx playwright test, or from the Actions tab on a branch with no open pull request into development. |
||||
| Hydra gates | ✅ |
Quality workflow — 2026-10-12 10:38 UTC
Download the full PDF report from the workflow artifacts.
…rt-import spec The fragment test was renamed to testTheMergedModuleIsVersion039WithTheExternalIds when the module schema moved to 0.3.9; the live spec still named the 038 test. The archived change keeps its historical name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Verdict: APPROVE (Thorough) — self-review posted as COMMENT (GitHub blocks self-APPROVE)
No blockers: the archive sheet is read under the CMDB sheets' bounds and the readBounded() refactor returns the same archive array in all three branches. The concerns are about silent gaps (uncached formulas, untested bounds) that matter once #1286 acts on these APPIDs.
Update 2026-10-12: All three concerns were fixed on the branch after posting; the four minors stay open as follow-ups.
🟡 Concerns (3)
- Uncached archive-sheet formulas vanish without a warning —
lib/Service/Cmdb/CmdbWorkbookReader.php:366. 🟡 Concern — the archive sheet drops a formula without a cached value silently, and reportspresent: truewith fewer APPIDs The archive sheet is formula-derived: the new fixture's APPID cell is<f>..</f><v>1234</v>(build-fixtures.py,archive_appid). ✅ Addressed in16337d91. - Archive sheet bounds now apply to imports that keep —
lib/Service/Cmdb/CmdbWorkbookReader.php:187. 🟡 Concern — an export that imports today can be refused because of a sheet the admin chose not to act onread()takes no mode, so from this slice on every import, includingmissingRecords=keep, loads the archive sheet and enforces on it the part-size bound (here), the row span, the referenced-string budget andTOO_MANY_ROWS. ✅ Addressed incdbec3d3 (#1287). - 'Same bounds as the CMDB sheets' is tested for one of five bounds —
tests/Unit/Service/Cmdb/CmdbWorkbookReaderTest.php:1005. 🟡 Concern — the totality promise "the archive sheet is read under the same bounds as the CMDB sheets, APPID column only" has one test REQ-CMDB-015, design D3 and the PR body promise that. ✅ Addressed in11d9a23c.
🟢 Minor (4)
- tasks.md ticks tasks whose code is in #1286/#1287 —
openspec/changes/cmdb-import-archive-reconciliation/tasks.md:37. 🟡 Concern — tasks 3 to 7 are marked implemented and tested in a PR that contains none of that codetasks.mdticks[x] Implementand[x] Testfor Task 3 (matching revives,CmdbExportImportService.php,CmdbImportReport.php), Task 4 (reconciliation), Task 5 (controller option), Task 6 (settings section) and Task 7 (fixture, docs; only its Test is open). - Referenced-string budget shrinks for workbooks without the archive sheet —
lib/Service/Cmdb/CmdbWorkbookReader.php:313. 🟢 Minor —count($profile->readSheetNames())always counts the archive sheet, also when the workbook has noneassertReferencedStringBytesdividesmaxReferencedStringBytesbysheetCount(CmdbWorkbookBounds.php:207). - appIds are raw cell values, not match keys —
lib/Service/Cmdb/CmdbWorkbookReader.php:366. 🟢 Minor —archive.appIdsholds raw typed cell values; say so, or normalise Read-only probe: cells7.0,' 8 ','app-9'come back as7(int),' 8 'and'app-9'. - Profile accepts 'archive' while the endpoint still refuses it —
lib/Settings/cmdb-import/topdesk-profile.json:48. 🟢 Minor — heads-up: until #1286 merges, the profile and the endpoint disagree The profile now lists["keep", "archive"]andmissingRecordsModes()reads it, but nothing inlib/callsmissingRecordsModes()on this head (only the unit test does):CmdbExportImportService::supportsMissingRecords()is still$mode === 'keep'andCmdbImportControllerstill answersdetails.accepted: ['keep'].
✅ Fixed before posting (1)
- Renamed test is still named by the live spec — fixed in
388181a.
✅ Verified clean
readBounded()refactor: the returnedarchivearray matches the pre-refactor version (softwarecatalog141ea249) for no sheet, a sheet without the key column and a sheet with it — checked by reading and a read-only probe.- Schema bumps module 0.3.9 / usage 1.5.7 follow the fragment-version convention and are pinned by
TopdeskCmdbFragmentTestandPublicationFieldRulesTest. x-openregister-archivematches OpenRegister'sSchema::ARCHIVE_ANNOTATION.
Scope decision: slice 1 of 3 of the closed #1281, stacked on development; reviewed against its own base only.
Gates: CI quality / Hydra Gates and the required PHP/Vue quality checks green on {h}; quality / PHPUnit was still running at submission.
ADRs verified: ADR-005, ADR-031, ADR-032, ADR-037 — all resolve on hydra main.
Jira context: WOO-587 — CMDB-import: gearchiveerde en verdwenen applicaties bij herimport (status: Refinement)
Quality Report — ConductionNL/stackiq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue-demi | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 133/133 | |||
| npm | ✅ | ✅ 807/807 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| lockfile sync | ✅ | ||||
| PHPUnit | ✅ 1233/1233 · 20 skipped | ||||
| Newman | ⏭️ | ||||
| Playwright | ⏭️ deferred: E2E runs locally and on the promotion path only. This pull request targets development, so the suite is asked once per promotion into beta and main rather than once per push per open pull request. Run it locally with npx playwright test, or from the Actions tab on a branch with no open pull request into development. |
||||
| Hydra gates | ✅ |
Quality workflow — 2026-10-12 12:53 UTC
Download the full PDF report from the workflow artifacts.
The archive sheet is formula-derived. A row whose APPID formula carries no cached value read as an empty row and was skipped without trace, so the sheet reported present: true with one APPID fewer. The reconciliation would then see that application on no sheet and soft-delete it instead of archiving it, with nothing in the report saying why. REQ-CMDB-002 already treats such a cell on the CMDB sheets as empty plus a row warning. readRows() now hands back the numbers of rows that read as empty only because a formula in them is uncached, and the reader returns them as archive.uncachedRows. The spec delta (REQ-CMDB-015, new scenario), design D3/D5 and task 2 state the rule: such a sheet is incomplete, so the import warns naming the sheet and rows and archives every missing application, deleting none. The service side follows in the stacked PR. Review #1285 f1 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
REQ-CMDB-015 and design D3 promise that the archive sheet is read under the same bounds as the CMDB sheets, for its key column only, but only the row limit had a test. The part size, the row span, the referenced-string budget, the key-only read filter and the null cases of archiveSheetName() could regress unnoticed; swapping readSheetNames() for sheetNames() in read() left the reader tests green, which would blank an oversized archive sheet instead of refusing it. Adds one test per bound. RecordingXlsxReader now also keeps the read filter of each load, so the key-only claim is asserted on what the data pass is allowed to read, not on the returned array. Each test was checked by mutating the reader (archive sheet left out of that bound) and goes red. Review #1285 f5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rule "archive, never soft-delete" was written as "when the workbook has no archive sheet" in the design risk list, the proposal summary and Risk 2, and in task 4. It also applies when the sheet has no APPID column or holds an APPID the reader cannot see (a formula without a cached value). Review pre-push p1 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
D8 said the facet narrowing's _ids composes with the Archived quick filter. The Archived tab of the Applications page overrides _ids with an empty value, so it lists the whole archive and ignores facets and search. Review pre-push p2 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ry import The docs said the import "ignores all other sheets" and that a sheet it does not read may exceed the part size limit. The archive sheet is read (its APPID column only) in every import, also with Keep, so it counts against the row span and part-size limits like a CMDB sheet and can refuse a keep import. The file section, the row limit, the part-size limit and the WORKBOOK_TOO_LARGE row now say so, and that deleting the sheet from a copy makes the import archive and never delete. Review #1285 f2 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Quality Report — ConductionNL/stackiq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue-demi | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 133/133 | |||
| npm | ✅ | ✅ 807/807 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| lockfile sync | ✅ | ||||
| PHPUnit | ✅ 1239/1239 · 20 skipped | ||||
| Newman | ⏭️ | ||||
| Playwright | ⏭️ deferred: E2E runs locally and on the promotion path only. This pull request targets development, so the suite is asked once per promotion into beta and main rather than once per push per open pull request. Run it locally with npx playwright test, or from the Actions tab on a branch with no open pull request into development. |
||||
| Hydra gates | ✅ |
Quality workflow — 2026-10-12 16:18 UTC
Download the full PDF report from the workflow artifacts.
… document the reader's bounds Closes the review findings: - "design D8 describes UI code not in this PR": D8 now says the UI code lands in #1287. - tasks.md ticked Implement/Test for Tasks 3-7 whose code is not in this PR: unticked, with a status note that they land in #1286 and #1287. - CmdbWorkbookReader sheet count always includes the archive sheet: documented in the read() docblock (limit / 3 is deliberate). - appIds are raw cell values: documented as raw, untrimmed and un-normalised; no consumer exists in this PR, so no code change. Class sweep: docs/features/cmdb-import.md described the referenced-string bound as "once per CMDB sheet"; it now names the archive sheet too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Quality Report — ConductionNL/stackiq @
|
| Check | PHP | Vue | Security | License | Tests |
|---|---|---|---|---|---|
| lint | ✅ | ||||
| phpcs | ✅ | ||||
| phpmd | ✅ | ||||
| psalm | ✅ | ||||
| phpstan | ✅ | ||||
| phpmetrics | ✅ | ||||
| eslint | ✅ | ||||
| stylelint | ✅ | ||||
| build | ✅ | ||||
| check-manifest | ✅ | ||||
| check-vue-demi | ✅ | ||||
| test-l10n | ✅ | ||||
| format | ✅ | ||||
| check-schema-l10n | ✅ | ||||
| check-l10n-js | ✅ | ||||
| composer | ✅ | ✅ 133/133 | |||
| npm | ✅ | ✅ 807/807 | |||
| app:check-code | ⏭️ | ||||
| info.xml | ✅ | ||||
| REUSE | ❌ | ||||
| lockfile sync | ✅ | ||||
| PHPUnit | ✅ 1239/1239 · 20 skipped | ||||
| Newman | ⏭️ | ||||
| Playwright | ⏭️ deferred: E2E runs locally and on the promotion path only. This pull request targets development, so the suite is asked once per promotion into beta and main rather than once per push per open pull request. Run it locally with npx playwright test, or from the Actions tab on a branch with no open pull request into development. |
||||
| Hydra gates | ✅ |
Quality workflow — 2026-10-13 17:29 UTC
Download the full PDF report from the workflow artifacts.
WilcoLouwerse
left a comment
There was a problem hiding this comment.
Verdict: APPROVE (Standard) — self-review posted as COMMENT (GitHub blocks self-APPROVE)
Nothing left to address: the one new minor and the four open minors from round 1 were fixed on the branch before posting. All 7 threads are resolved. What still stands between this PR and a merge: 1 approval, and the CI run on
ae31ac3, which started with this push.
| Round | Found | Status |
|---|---|---|
1 (388181a) |
🟡 uncached archive formulas vanished · 🟡 archive bounds applied to keep · 🟡 'same bounds' tested for 1 of 5 · 🟢 tasks.md ticks · 🟢 string budget · 🟢 raw appIds · 🟢 profile vs endpoint | 3 🟡 resolved in 16337d9/11d9a23; 3 🟢 resolved in ae31ac3; 1 🟢 needed no change (#1286) |
2 (ae31ac3) — this review |
🟢 design D8 described UI code from #1287 | fixed before posting in ae31ac3 |
| Finding | Was | Now | Where |
|---|---|---|---|
| 🟢 tasks.md ticks tasks whose code is in #1286/#1287 | 🟢 r1 | resolved in ae31ac3 |
thread |
| 🟢 Referenced-string budget shrinks for workbooks without the archive sheet | 🟢 r1 | resolved in ae31ac3 (documented; docs copy corrected) |
thread |
| 🟢 appIds are raw cell values, not match keys | 🟢 r1 | resolved in ae31ac3 (documented) |
thread |
| 🟢 Profile accepts 'archive' while the endpoint still refuses it | 🟢 r1 | no change needed: #1286 makes the endpoint accept it | thread |
| 🟢 Design D8 describes UI code not in this PR | new | fixed before posting in ae31ac3 |
openspec/changes/cmdb-import-archive-reconciliation/design.md:118 |
Details of this round
Scope decision: delta 388181a…70d6f93 (4 commits, 7 files, 281 changed lines), plus the fix commit ae31ac3 written in this run.
✅ Fixed before posting (1)
- Design D8 describes UI code not in this PR —
ae31ac3: D8 now says the quick filters, the_idsoverride and thesrc/icons.jsentry land in #1287.
Verified at 70d6f93: 16337d9's $unseen branch is on the live path and covered by testAnUncachedArchiveKeyIsListedNotDropped. The archive-only rule reads the same in proposal, design, tasks and spec.
Gates: CI quality / Hydra Gates ✅ on 70d6f93. CI on ae31ac3 was still running when this verdict was posted. ae31ac3 changes docblock and Markdown text only. phpcs on CmdbWorkbookReader.php is clean; PHPUnit was not run for it.
Jira context: WOO-587, CMDB import: archived and vanished applications on re-import.
What
First of three stacked PRs that replace #1281 (archive or soft-delete applications that left a newer CMDB export). This slice reads the archive sheet; nothing acts on it yet.
cmdb-import-archive-reconciliation: ADDED REQ-CMDB-015..017, MODIFIED REQ-CMDB-012 and REQ-CMDB-014. The design records why object state is read per lens and from the trash (D9).module(0.3.9) andusage(1.5.7) opt in to archiving throughx-openregister-archive. Run Force Update after installing.missingRecordsmodes (keep,archive), readable before the packs are validated.topdesk-archived-applications.xlsx, a later export in which APPID 1234 moved to the archive sheet and APPID 2 is on no sheet.Stack
developmentJira: WOO-587 (sub-task of WOO-586). Plan: WOO-587 plan. Review and merge are tracked in WOO-590.
Review fixes (2026-10-12)
388181a316337d91uncachedRows), not dropped; the spec delta, design D3/D5 and task 2 say what follows (archive, never delete — #1286).11d9a23carchiveSheetName()null cases), each mutation-checked.aa3b6648,70d6f934Tests
🤖 Generated with Claude Code