Skip to content

feat: rename to requirements specification - #153

Merged
johlju merged 9 commits into
viscalyx:mainfrom
johlju:f/rename-to-spec
May 3, 2026
Merged

feat: rename to requirements specification#153
johlju merged 9 commits into
viscalyx:mainfrom
johlju:f/rename-to-spec

Conversation

@johlju

@johlju johlju commented May 3, 2026

Copy link
Copy Markdown
Member

Description

This changes all files but the integration tests, skills and instructions, they have been hold back on purpuse to limit the changeset of # of files.

Screenshots (if applicable)

Related Issues

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Performance improvement (improves performance without changing functionality)
  • Dependency update (updating libraries or tools)

Testing

  • npm run check passes locally
  • All existing tests still pass
  • Manual testing completed
  • UI tested on desktop and mobile (if applicable)

Checklist

  • Documentation updated as needed

Checklist

  • Code follows the project style guidelines (Biome)
  • Tests added/updated as needed
  • Self-review of code completed
  • Comments added for complex logic
  • No hardcoded strings (use translations if i18n is added)

This change is Reviewable

@coderabbitai

coderabbitai Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Renames and retargets the "package" domain to "specification" across the codebase: DB schema, TypeORM entities, DAL, API routes, services, hooks, clients, UI, reports, i18n, seeds, migrations, and tests; all package-scoped endpoints/fields are replaced by specification-scoped equivalents.

Changes

Packages → Specifications Refactor

Layer / File(s) Summary
DB schema & migrations
typeorm/migrations/*, typeorm/seed*.mjs
Introduces specification tables (requirements_specifications, specification_local_requirements, specification_item_statuses, etc.), updates deviations FK to reference specification items, and updates seeds.
TypeORM entities registry
lib/typeorm/entities/*, lib/typeorm/entities/index.ts
Removes package entities, adds RequirementsSpecification* and Specification* entity schemas, updates entity exports and indices.
DAL: data shapes & core logic
lib/dal/requirements-specifications.ts, lib/dal/deviations.ts, lib/dal/specification-*.ts
Replaces package DAL with specification DAL: new item-ref types, spec-local CRUD, linking/unlinking (requirements_specification_items), deviation workflows and counts rebuilt for specification tables.
API routes
app/api/specifications/**, app/api/specification-*/*, app/api/catalog/specification-item-statuses/**, app/api/specification-local-deviations/**
Retargets package-prefixed endpoints to specification counterparts; handlers now call specification DAL functions and return spec-shaped payloads.
Service surface & auth
lib/requirements/service.ts, lib/requirements/auth.ts, lib/requirements/types.ts
Public APIs and action unions refactored: listSpecifications, getSpecificationItems, addToSpecification, removeFromSpecification; types use specificationId/specificationSlug and specificationItemId/specificationCount.
App pages & clients
app/[locale]/specifications/**, app/[locale]/specification-item-statuses/*, app/[locale]/admin/admin-client.tsx, components/Navigation.tsx
Adds specification pages/clients, removes or replaces package pages; admin navigation/cards now point to /specifications and spec-admin pages.
Requirement-detail / hooks / dialogs
app/[locale]/requirements/[id]/_detail/*, requirement-detail-client.tsx
Swaps package-item context for specification-item context: useSpecificationItemContext, useAddToSpecificationDialog, SpecificationDeviationRail, dialog/hook renames and wiring updates.
Specification detail & edit panel
app/[locale]/specifications/[slug]/requirements-specification-detail-client.tsx, specification-edit-panel.tsx
Converts package-detail client to specification-detail: fetch/patch /api/specifications/*, link/unlink items, spec-local create/update/delete, CSV/report filename and PDF building updated.
UI table & status select
components/RequirementsTable.tsx, components/_requirements-table/SpecificationItemStatusSelect.tsx, lib/requirements/list-view.ts
Replaces package-item-status column/filter/props with specificationItemStatus equivalents; updates row shape, props, and adds SpecificationItemStatusSelect and new status option types.
Local requirement components
components/SpecificationLocalRequirementDetailClient.tsx, components/SpecificationLocalRequirementForm.tsx
Renamed and rewired local-requirement detail/form to spec-local endpoints; props use specificationSlug; mutability/guarding uses DEFAULT_SPECIFICATION_ITEM_STATUS_ID.
Reports & templates
lib/reports/*, components/reports/*, app/[locale]/specifications/*/reports/*
Report fetchers, templates, and section discriminants switched to specification paths and specification-cover; metadata fields populated from specification responses.
Admin taxonomy CRUD
app/[locale]/specifications/*/implementation-types/*, lifecycle-statuses/*, responsibility-areas/*
Admin CRUD endpoints/clients retargeted to /api/specification-* endpoints and new DAL modules.
i18n, docs & tooling
messages/*.json, messages/sv.json, docs/**, cspell.jsonc, README.md, devfile.yaml
All user-facing keys, docs, architecture diagrams, spellcheck words, seed docs and developer docs updated to use "specification"/"kravunderlag" terminology and new routes.
Tests
tests/**/*
Extensive unit/integration/functional test updates to reflect specification semantics; added spec-item-statuses DAL tests and many spec-route tests; fixtures and expectations changed to specification-shaped payloads.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Browser as Client
    participant NextAPI as Next.js API
    participant Service as Requirements Service
    participant DAL as DAL
    participant DB as SQL Server
    Browser->>NextAPI: POST /api/specifications/{slug}/items (add requirements)
    NextAPI->>Service: addToSpecification(input)
    Service->>DAL: linkRequirementsToSpecificationAtomically(specId, requirementIds)
    DAL->>DB: INSERT requirements_specification_items + (maybe) specification_needs_references (transaction)
    DB-->>DAL: OK / inserted ids
    DAL-->>Service: { addedCount, skippedCount, skippedIds }
    Service-->>NextAPI: { addedCount, skippedCount, message }
    NextAPI-->>Browser: 200 OK { summary }
Loading
sequenceDiagram
    autonumber
    participant Browser as Client
    participant NextAPI as Next.js API
    participant DAL as DAL
    participant DB as SQL Server
    Browser->>NextAPI: GET /api/specification-item-deviations/{itemId}
    NextAPI->>DAL: listDeviationsForSpecificationItem(itemId)
    DAL->>DB: SELECT union deviations + specification_local_requirement_deviations
    DB-->>DAL: rows
    DAL-->>NextAPI: normalized rows (isSpecificationLocal, itemRef, spec metadata)
    NextAPI-->>Browser: 200 OK [deviations]
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

Possibly related PRs

@codecov

codecov Bot commented May 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 60.07984% with 400 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.49%. Comparing base (9b27eb4) to head (a4cde12).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
[...slug]/requirements-specification-detail-client.tsx](https://app.codecov.io/gh/viscalyx/Kravhantering/pull/153?src=pr&el=tree&filepath=app%2F%5Blocale%5D%2Fspecifications%2F%5Bslug%5D%2Frequirements-specification-detail-client.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=viscalyx#diff-YXBwL1tsb2NhbGVdL3NwZWNpZmljYXRpb25zL1tzbHVnXS9yZXF1aXJlbWVudHMtc3BlY2lmaWNhdGlvbi1kZXRhaWwtY2xpZW50LnRzeA==) 49.25% 67 Missing and 1 partial ⚠️
lib/dal/specification-item-statuses.ts 19.14% 38 Missing ⚠️
lib/dal/requirements-specifications.ts 75.19% 32 Missing ⚠️
lib/requirements/service.ts 54.23% 27 Missing ⚠️
...pp/api/specifications/[id]/items/[itemId]/route.ts 70.42% 21 Missing ⚠️
lib/dal/specification-implementation-types.ts 0.00% 20 Missing ⚠️
lib/dal/specification-responsibility-areas.ts 0.00% 20 Missing ⚠️
lib/dal/deviations.ts 37.03% 16 Missing and 1 partial ⚠️
.../[locale]/specifications/specifications-client.tsx 81.08% 10 Missing and 4 partials ⚠️
.../api/specifications/[id]/needs-references/route.ts 0.00% 14 Missing ⚠️
... and 27 more
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #153      +/-   ##
==========================================
+ Coverage   58.66%   59.49%   +0.83%     
==========================================
  Files         292      292              
  Lines       17133    17230      +97     
  Branches     6560     6514      -46     
==========================================
+ Hits        10051    10251     +200     
+ Misses       6961     6856     -105     
- Partials      121      123       +2     
Files with missing lines Coverage Δ
app/[locale]/admin/admin-client.tsx 91.89% <ø> (ø)
...equirements/[id]/_detail/RequirementActionRail.tsx 63.02% <100.00%> (ø)
...equirements/[id]/_detail/RequirementReportMenu.tsx 72.34% <100.00%> (ø)
...ements/[id]/_detail/SpecificationDeviationRail.tsx 68.42% <100.00%> (ø)
app/[locale]/requirements/[id]/_detail/types.ts 100.00% <ø> (ø)
app/[locale]/requirements/requirements-client.tsx 83.06% <ø> (ø)
...em-statuses/specification-item-statuses-client.tsx 84.95% <100.00%> (ø)
.../[locale]/specifications/[slug]/reports/layout.tsx 0.00% <ø> (ø)
...plementation-types/implementation-types-client.tsx 100.00% <ø> (ø)
[...cale]/specifications/implementation-types/page.tsx](https://app.codecov.io/gh/viscalyx/Kravhantering/pull/153?src=pr&el=tree&filepath=app%2F%5Blocale%5D%2Fspecifications%2Fimplementation-types%2Fpage.tsx&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=viscalyx#diff-YXBwL1tsb2NhbGVdL3NwZWNpZmljYXRpb25zL2ltcGxlbWVudGF0aW9uLXR5cGVzL3BhZ2UudHN4) 0.00% <ø> (ø)
... and 77 more
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (18)
docs/dogfood-seed.md (1)

90-104: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Finish the terminology rename in the KH/KH-POC prose.

This section still uses “package” wording in sentences describing the two
Kravunderlag. Replace those remaining mentions with “specification” terms so
the section is consistent with the updated table/entity names.

Suggested wording adjustments
- The main package containing all 59 Krav from the dogfood inventory.
+ The main specification containing all 59 Krav from the dogfood inventory.

- sit on top of this package to demonstrate PoC-specific divergence
+ sit on top of this specification to demonstrate PoC-specific divergence
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/dogfood-seed.md` around lines 90 - 104, The prose under the
"Kravunderlag" section still uses the word "package" when describing `KH` and
`KH-POC`; update those sentences to use "specification" (or "specification"
phrasing) instead to match the renamed entities, e.g., change "The main package
containing..." to "The main specification containing..." and "A smaller curated
subset (17 Krav) that demonstrates the *Införande* lifecycle" to reference
`KH-POC` as a specification; keep the references to
`specification_local_requirements` as-is and ensure all occurrences of "package"
in this block (including the two sentences describing `KH` and `KH-POC`) are
replaced with consistent "specification" terminology.
app/api/specifications/route.ts (1)

1-33: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

API route path conflicts with locale-captured segment naming.

This route uses /api/specifications, while app/[locale]/specifications/... exists.
Per project routing safety rules, this can be captured by [locale] and return HTML
404 instead of the API handler in affected setups. Move this API namespace to a
conflict-free second segment and update callers.

As per coding guidelines, "Do not place API routes at paths that can be matched by app/[locale]/... ... Use conflict-free top-level nouns if there is overlap."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/specifications/route.ts` around lines 1 - 33, This API route
conflicts with app/[locale]/specifications because the top-level segment
"specifications" can be captured by [locale]; move the endpoint to a
conflict-free second segment (e.g., change the public path from
/api/specifications to /api/v1/specifications or /api/internal/specifications),
update all callers to the new path, and keep the existing handler functions GET
and POST (and their usage of createPackage, isSlugTaken, listPackages,
getRequestSqlServerDataSource) unchanged so only the route namespace changes.
docs/reports.md (1)

56-66: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use one domain term consistently (“specification”) in this report doc.

These updated sections still mix package/specification wording (detail view,
context refs, and filename template). Please normalize terminology so route/data
contract descriptions stay unambiguous.

Example normalization
- Available from the print dropdown in the package detail view
+ Available from the print dropdown in the specification detail view

- Includes both library requirements linked into the package and
+ Includes both library requirements linked into the specification and

- package-context item references such as ...
+ specification-context item references such as ...

- List (package): `{localized label} {package name} {specification ID}.pdf`
+ List (specification): `{localized label} {specification name} {specification ID}.pdf`

Also applies to: 155-163, 187-188

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/reports.md` around lines 56 - 66, The doc mixes "package" and
"specification" terms; standardize to use "specification" everywhere: update
phrases like "package detail view", "package metadata", "package name",
"package-local requirements", "package detail", and the filename template to
read "specification" (e.g., "specification detail view", "specification
metadata", "specification-local requirements"); also update route and context
descriptions such as "Print opens a dedicated route; PDF is generated inline in
the package detail view" to reference the specification route/view consistently,
and apply the same normalization to the other referenced sections that currently
use mixed terminology.
app/[locale]/specifications/specifications-client.tsx (1)

320-339: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle taxonomy fetch failures independently.

A single rejected request here aborts the entire Promise.all(...), so one flaky taxonomy endpoint leaves all three dropdowns empty and produces an unhandled rejection from the effect. Using per-request handling or Promise.allSettled(...) would preserve partial data and let you surface a controlled error state.

Suggested direction
-    const [areasRes, typesRes, statusesRes] = await Promise.all([
+    const [areasRes, typesRes, statusesRes] = await Promise.allSettled([
       apiFetch('/api/specification-responsibility-areas'),
       apiFetch('/api/specification-implementation-types'),
       apiFetch('/api/specification-lifecycle-statuses'),
     ])
-    if (areasRes.ok && isMountedRef.current)
+    if (areasRes.status === 'fulfilled' && areasRes.value.ok && isMountedRef.current)
       setResponsibilityAreas(
-        ((await areasRes.json()) as { areas?: TaxonomyItem[] }).areas ?? [],
+        ((await areasRes.value.json()) as { areas?: TaxonomyItem[] }).areas ?? [],
       )
-    if (typesRes.ok && isMountedRef.current)
+    if (typesRes.status === 'fulfilled' && typesRes.value.ok && isMountedRef.current)
       setImplementationTypes(
-        ((await typesRes.json()) as { types?: TaxonomyItem[] }).types ?? [],
+        ((await typesRes.value.json()) as { types?: TaxonomyItem[] }).types ?? [],
       )
-    if (statusesRes.ok && isMountedRef.current)
+    if (statusesRes.status === 'fulfilled' && statusesRes.value.ok && isMountedRef.current)
       setLifecycleStatuses(
-        ((await statusesRes.json()) as { statuses?: TaxonomyItem[] })
+        ((await statusesRes.value.json()) as { statuses?: TaxonomyItem[] })
           .statuses ?? [],
       )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/`[locale]/specifications/specifications-client.tsx around lines 320 -
339, fetchTaxonomies uses Promise.all so one failing apiFetch aborts all three
and causes unhandled rejections; change it to handle each request independently
(e.g., use Promise.allSettled or wrap each apiFetch in try/catch) and for each
result check ok and isMountedRef.current before calling setResponsibilityAreas,
setImplementationTypes, or setLifecycleStatuses, parse JSON only when the
response is ok, set an empty default when a single request fails, and
surface/log per-endpoint errors so one flaky taxonomy endpoint doesn't clear all
dropdowns.
app/[locale]/specifications/[slug]/specification-edit-panel.tsx (1)

116-120: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add the same submit re-entry guard used in the list client.

This handler does not bail out when isSubmitting is already true, so a quick double submit can send two PUTs and fire onSaved twice before the button disable propagates.

Suggested fix
   const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
     event.preventDefault()
+    if (isSubmitting) return
     setIsSubmitting(true)
     setSlugError(null)
     setSubmitError(null)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/`[locale]/specifications/[slug]/specification-edit-panel.tsx around lines
116 - 120, The submit handler handleSubmit should bail out immediately if a
submission is already in progress to prevent duplicate PUTs; add a re-entry
guard at the top of handleSubmit that checks the isSubmitting state and returns
early when true, keeping the existing event.preventDefault() behavior and state
updates (setIsSubmitting, setSlugError, setSubmitError) intact; ensure the rest
of the function still sets setIsSubmitting(true) only when proceeding and that
setIsSubmitting(false) is called on error/after completion so the guard remains
effective.
typeorm/seed.mjs (1)

664-667: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep this needs reference consistent with the seeded specification.

requirements_specifications row 9 is a development initiative (APIGW-UTV-2026), but this text still describes a procurement. That makes the representative seed data internally contradictory.

Suggested fix
-        'Rate limiting är ett primärt krav för API-gateway-upphandlingen',
+        'Rate limiting är ett primärt krav för API-gateway-utvecklingen',

As per coding guidelines, "Ensure every table in the schema has representative, idempotent seed rows" and "Preserve current seed-data meaning and identifiers wherever possible."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@typeorm/seed.mjs` around lines 664 - 667, The seeded row in
requirements_specifications that uses spec id 9 currently describes a
procurement but must match the development initiative APIGW-UTV-2026; update the
text value (the string currently "Rate limiting är ett primärt krav för
API-gateway-upphandlingen") to a development-focused phrasing (e.g., mention
implementation or development for APIGW-UTV-2026) while leaving the numeric
identifiers (21, 9) and the timestamp '2026-04-17 20:07:00' unchanged so the
seed remains idempotent and consistent with the spec.
typeorm/seed-dogfood-build.mjs (1)

292-312: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

specification_local_requirements rows are one column too wide.

Line 309-Line 312 append four trailing timestamps after note, but the specification-local schema only has three trailing timestamp columns (status_updated_at, created_at, updated_at). That leaves every seeded local requirement row with one extra cell, which can misalign column-based inserts.

Suggested fix
     locals.rows.push([
       localId,
       pl.pkg,
       uniqueId,
       seq,
       k.area,
       k.desc + (pl.descSuffix || ''),
       k.ac + (pl.acSuffix || ''),
       k.cat,
       k.type,
       k.qc,
       k.risk,
       k.test ? 1 : 0,
       k.vm,
       needsRefId,
       pl.item,
       pl.note || null,
       SEED_TS,
       SEED_TS,
       SEED_TS,
-      SEED_TS,
     ])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@typeorm/seed-dogfood-build.mjs` around lines 292 - 312, The array pushed in
locals.rows (the array starting with localId, pl.pkg, ... , pl.note || null,
SEED_TS, SEED_TS, SEED_TS, SEED_TS) is one element too wide; remove the extra
trailing SEED_TS so only three timestamps remain to match the
specification_local_requirements columns (status_updated_at, created_at,
updated_at). Locate the array push (the locals.rows.push call) and delete the
fourth SEED_TS after pl.note || null so the inserted row has exactly three
trailing timestamp values.
app/api/specifications/[id]/report-items/route.ts (1)

1-192: ⚠️ Potential issue | 🟠 Major

Move this endpoint family out of app/api/specifications.

The repo already has locale-routed pages under app/[locale]/specifications/... (page.tsx, [slug]/page.tsx, and subpaths), creating a path conflict with this /api/specifications/... endpoint. App Router's dynamic [locale] segment can match "api" and cause requests to resolve through locale routing and return HTML/404 instead of this JSON handler. Move to a conflict-free top-level noun in app/api/ (e.g., app/api/specification-reports/...).

As per coding guidelines: "Do not place API routes at paths that can be matched by app/[locale]/.... Turbopack's [locale] dynamic segment captures every path segment including api, returning a 404 HTML page instead of the route handler."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/specifications/`[id]/report-items/route.ts around lines 1 - 192, This
API endpoint (route.ts with exported GET) lives under app/api/specifications/...
which conflicts with app/[locale]/specifications dynamic routing; move the
entire folder and its route.ts to a top-level, locale-safe path such as
app/api/specification-reports/[id]/report-items/route.ts (or similar) so
requests hit the JSON handler; after moving, update any callers/clients that
request /api/specifications/... to the new path and ensure imports referencing
functions like GET, parsePackageItemRef, getPackageById,
getSpecificationLocalRequirementDetail, and
mapSpecificationLocalRequirementToReportData remain correct (adjust relative
paths if you moved helper modules) and run tests to validate the new route.
typeorm/migrations/0001_initial_sqlserver.mjs (1)

4-152: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Don't rewrite already-applied migrations for this rename.

This changes 0001 in place, so databases that have already recorded InitialSqlServerSchema1713720000000 will never see these table/column/FK renames. They will keep the old package-named schema while the renamed entities and routes now target requirements_specifications, requirements_specification_items, etc., which makes upgrades break. Please restore the historical migrations and add a new forward migration that renames the existing objects with sp_rename/ALTER TABLE instead. As per coding guidelines, "Migrations live in typeorm/migrations/ (one .mjs file per migration)." and "Prefer SQL Server ALTER TABLE … ADD, ALTER COLUMN, and sp_rename over drop-and-recreate for renames and additions in migrations to keep foreign key safety."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@typeorm/migrations/0001_initial_sqlserver.mjs` around lines 4 - 152, The
migration 0001 (InitialSqlServerSchema1713720000000) was modified in place to
rename tables/columns (e.g., requirements_specifications,
requirements_specification_items) which breaks upgrades for DBs that already
applied the original migration; revert the historical 0001 migration back to its
original state (restore original table/column/FK names in the existing
0001_initial_sqlserver.mjs) and create a new forward migration file that
performs the renames using SQL Server-safe statements (sp_rename, ALTER TABLE
... ADD/ALTER COLUMN, and ALTER TABLE ... DROP/ADD CONSTRAINT where necessary)
to rename each affected object and update FKs rather than dropping/recreating
them so existing databases will see the changes during migration.
lib/dal/specification-item-statuses.ts (1)

60-69: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

The linked-status lookup is broken and incomplete.

requirements_specification_items uses
requirements_specification_id, not specification_id, so the join in
getLinkedPackageItems() will fail. On top of that, both linked-usage
queries only inspect requirements_specification_items, even though
specification_local_requirements also carries
specification_item_status_id, so linked counts/details are underreported
and a delete can clear local statuses without warning.

Also applies to: 90-99

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/dal/specification-item-statuses.ts` around lines 60 - 69, The
linked-status queries are wrong: change any join/filter that references
specification_id to use requirements_specification_id and include both sources
that carry specification_item_status_id (requirements_specification_items and
specification_local_requirements) so counts and details include both tables;
update countLinkedPackageItems and getLinkedPackageItems to aggregate (e.g.,
UNION ALL or two-source JOIN/UNION) across requirements_specification_items and
specification_local_requirements using requirements_specification_id as the FK
and group by specification_item_status_id (or statusId) to produce correct
linked counts and avoid underreporting or missing deletes.
app/api/specifications/[id]/local-requirements/[localRequirementId]/route.ts (1)

206-215: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Map DELETE failures to JSON as well.

Line 206 calls the DAL without a catch block, so database/service failures bypass the error handling pattern you already use in PUT and return a framework 500 instead of a stable JSON payload.

Suggested fix
-  const deleted = await deleteSpecificationLocalRequirement(
-    db,
-    specificationId,
-    numericLocalRequirementId,
-  )
-  if (!deleted) {
-    return NextResponse.json({ error: 'Not found' }, { status: 404 })
-  }
-
-  return NextResponse.json({ ok: true })
+  try {
+    const deleted = await deleteSpecificationLocalRequirement(
+      db,
+      specificationId,
+      numericLocalRequirementId,
+    )
+    if (!deleted) {
+      return NextResponse.json({ error: 'Not found' }, { status: 404 })
+    }
+
+    return NextResponse.json({ ok: true })
+  } catch (error) {
+    if (isRequirementsServiceError(error)) {
+      return NextResponse.json(
+        { error: error.message },
+        { status: error.status },
+      )
+    }
+
+    console.error('Failed to delete specification-local requirement', error)
+    return NextResponse.json(
+      { error: 'Failed to delete specification-local requirement' },
+      { status: 500 },
+    )
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/specifications/`[id]/local-requirements/[localRequirementId]/route.ts
around lines 206 - 215, The delete path currently calls
deleteSpecificationLocalRequirement(db, specificationId,
numericLocalRequirementId) with no error handling so DB/service exceptions
escape and produce a framework 500; wrap that call in a try/catch, return the
same JSON-shaped error responses you use in the PUT handler (e.g.,
NextResponse.json({ error: '...' }, { status: 500 }) for server errors) and keep
the existing 404 branch when deleted is falsy; reference
deleteSpecificationLocalRequirement, db, specificationId,
numericLocalRequirementId and NextResponse.json when making the change.
app/[locale]/requirements/[id]/_detail/RequirementActionRail.tsx (1)

179-188: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update the dev marker to the renamed action.

The button now renders the specification action, but the marker still publishes value: 'add to package', so Developer Mode/scanner consumers will keep seeing the old name.

Suggested fix
           {...devMarker({
             context: detailContext,
             name: 'detail action',
             priority: 360,
-            value: 'add to package',
+            value: 'add to specification',
           })}

As per coding guidelines, When changing visible UI elements, labels, roles, or layout surfaces, update curated devMarker(...) calls or scanner heuristics.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/`[locale]/requirements/[id]/_detail/RequirementActionRail.tsx around
lines 179 - 188, The devMarker call for the specification button still publishes
the old value 'add to package'; locate the devMarker(...) invocation inside
RequirementActionRail (the button that calls onOpenAddToSpecification and uses
detailContext/name 'detail action') and update the value field to the renamed
action (e.g., 'add to specification') so the scanner/dev-mode consumers match
the visible UI change, leaving the rest of the devMarker properties intact.
tests/unit/requirements-specification-detail-client.test.tsx (1)

368-375: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Rename the dev-marker expectation from edit package.

This suite now targets the specification detail view, but the asserted developer-mode value still uses the old term. That makes a partial rename look correct in tests.

Suggested expectation update
     expect(editButton).toHaveAttribute(
       'data-developer-mode-value',
-      'edit package',
+      'edit specification',
     )

As per coding guidelines, {tests/unit/**/*.{ts,tsx},tests/integration/**/*.spec.ts}: When changing visible UI elements, labels, roles, or layout surfaces, update the relevant unit and integration tests.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/requirements-specification-detail-client.test.tsx` around lines
368 - 375, Update the dev-marker expectation for the edit button: in
tests/unit/requirements-specification-detail-client.test.tsx change the asserted
data-developer-mode-value on editButton from 'edit package' to 'edit
specification' so the test reflects the specification detail view; locate the
assertion that calls
expect(editButton).toHaveAttribute('data-developer-mode-value', ...) and replace
the string accordingly.
tests/unit/requirements-service.test.ts (1)

1078-1108: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update these success-message assertions to specification.

The renamed service methods still pin the outward-facing text to Package, so this test will either fail once the copy is corrected or keep an incomplete rename green.

Suggested expectation update
     expect(JSON.parse(result.message)).toMatchObject({
-      lines: ['Added 1 requirement to package IAM-PACKAGE.'],
-      title: 'Requirements Added to Package',
+      lines: ['Added 1 requirement to specification IAM-PACKAGE.'],
+      title: 'Requirements Added to Specification',
     })

...

     expect(JSON.parse(result.message)).toMatchObject({
-      lines: ['Removed 1 requirement from package IAM-PACKAGE.'],
-      title: 'Requirements Removed from Package',
+      lines: ['Removed 1 requirement from specification IAM-PACKAGE.'],
+      title: 'Requirements Removed from Specification',
     })

As per coding guidelines, {tests/unit/requirements-service.test.ts,tests/unit/mcp-http.test.ts}: Update tests/unit/requirements-service.test.ts and tests/unit/mcp-http.test.ts for service or MCP output changes.

Also applies to: 1111-1129

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/requirements-service.test.ts` around lines 1078 - 1108, Update the
test assertions in tests/unit/requirements-service.test.ts that check the
outward-facing message from RequirementsService.addToSpecification: change
occurrences of "Package" to "Specification" and the lines text from "Added X
requirement to package <SPEC>." to "Added X requirement to specification
<SPEC>." Also update the JSON title expectation from 'Requirements Added to
Package' to 'Requirements Added to Specification' so the expected output from
addToSpecification and any uses of linkRequirementsToPackageAtomically remain
consistent with the renamed service wording.
lib/mcp/server.ts (1)

1319-1354: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Finish the MCP rename in the contract, not just in the tool IDs.

These tools are now exposed as ...specification..., but their descriptions, titles, several .describe(...) strings, and the list output schema still say package/packages. MCP clients read that metadata as the contract, so the current mix is misleading and leaves the outward-facing rename incomplete.

Representative fixes
- 'List all requirements specifications, optionally filtered by name. Returns id, uniqueId (slug), names, item count, responsibility area, and implementation type for each package.',
+ 'List all requirements specifications, optionally filtered by name. Returns id, uniqueId (slug), names, item count, responsibility area, and implementation type for each specification.',

- 'Case-insensitive substring filter applied to both Swedish and English package names.',
+ 'Case-insensitive substring filter applied to both Swedish and English specification names.',

- packages: z.array(
+ specifications: z.array(

- title: 'Get Package Items',
+ title: 'Get Specification Items',

- '... Identify the package with specificationId ...',
+ '... Identify the specification with specificationId ...',

- 'Numeric requirement IDs (not uniqueId strings) to add to the package.',
+ 'Numeric requirement IDs (not uniqueId strings) to add to the specification.',

- title: 'Add Requirements to Package',
+ title: 'Add Requirements to Specification',

- title: 'Remove Requirements from Package',
+ title: 'Remove Requirements from Specification',

As per coding guidelines, {lib/mcp/**/*.ts,lib/requirements/**/*.ts,lib/dal/**/*.ts,app/api/**/*.ts}: Keep MCP tool description, inputSchema, outputSchema, and field .describe(...) text aligned with the handler/service behavior.

Also applies to: 1385-1443, 1477-1529, 1563-1604

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/mcp/server.ts` around lines 1319 - 1354, The tool's public contract mixes
"package/packages" with "specification/specifications": update the title,
description string, all .describe(...) texts in the inputSchema, and the
outputSchema structure and field names so they consistently use "requirement
specification"/"requirements specification" (singular/plural) or the chosen
"specification" term; specifically adjust the tool title "List Requirements
Specifications", any description text, the inputSchema.nameSearch .describe(...)
string, and the outputSchema top-level field currently named "packages" and its
item property descriptions (e.g., businessNeedsReference, implementationType,
responsibilityArea, uniqueId) so the schema keys/describe strings and returned
message match the renamed concept across the handler and contract (ensure
z.object keys and z.describe strings reflect the new term and keep types
unchanged).
components/RequirementsTable.tsx (1)

2360-2412: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve the status label when no color is configured.

This branch only renders a value when specificationItemStatusColor is present. Since the color is nullable, rows with a valid status name but no configured color will look unset and show . Render the label whenever it exists, and only make the dot conditional.

Suggested fix
-            {statusColor ? (
+            {statusLabel ? (
               <span className="inline-flex items-center gap-1.5">
-                <span
-                  aria-hidden="true"
-                  className="inline-block w-2.5 h-2.5 rounded-full shrink-0"
-                  style={{ backgroundColor: statusColor }}
-                />
-                {statusLabel ?? '—'}
+                {statusColor ? (
+                  <span
+                    aria-hidden="true"
+                    className="inline-block w-2.5 h-2.5 rounded-full shrink-0"
+                    style={{ backgroundColor: statusColor }}
+                  />
+                ) : null}
+                {statusLabel}
               </span>
             ) : (
               '—'
             )}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/RequirementsTable.tsx` around lines 2360 - 2412, The display
branch for the 'specificationItemStatus' column currently shows the status label
only when specificationItemStatusColor is present, causing rows with a name but
no color to render '—'; change the rendering so the statusLabel is always shown
when non-null and only the colored dot (the inline-block with backgroundColor
using statusColor) is conditional on specificationItemStatusColor, keeping the
existing fallback '—' only when statusLabel is absent; locate this logic in the
return block that renders the <td> (near SpecificationItemStatusSelect and
variables statusId/statusLabel/statusColor) and adjust the JSX to render the
label unconditionally while wrapping the dot element in a condition on
statusColor.
lib/requirements/service.ts (1)

300-334: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Service output still mixes “package/paket” with “specification/kravunderlag”.

These helpers and summaries are returned to clients for list/get/add/remove flows, so the rename is still incomplete in API/MCP-facing output (Package Requirements, Added ... to package, ... från/fran paket, etc.). Please switch the remaining human-text generators to specification terminology consistently.

As per coding guidelines, "Update human-text generators in lib/requirements/service.ts and lib/mcp/server.ts when the property name or value appears in generated text."

Also applies to: 1635-1642, 1708-1713, 1804-1810, 1863-1867

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/requirements/service.ts` around lines 300 - 334, Update the human-facing
strings so they use "specification"/"kravunderlag" instead of "package"/"paket":
modify getPackageWord to return 'specification'/'specifications' for non-sv and
keep 'kravunderlag' for sv, and update getPackageServiceTitle (cases
'add','items','remove' and default) to use English phrases like "Specification
Added", "Specification Items" (or "Specifications" as appropriate) and Swedish
equivalents ("Krav tillagda i underlag" → change to use
"kravunderlag"/appropriate Swedish wording instead of "underlag/paket"); apply
the same string replacements in the corresponding generators in
lib/mcp/server.ts and the other locations listed (around the referenced ranges)
so all API/MCP-facing outputs consistently use specification/kravunderlag.
app/[locale]/specifications/[slug]/requirements-specification-detail-client.tsx (1)

101-130: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Version the persisted column preferences for the specification view.

This rename changes the saved column semantics, but the component still hydrates from the old requirement-packages.*.v2 keys and readStoredCols() accepts any stored array as-is. Existing users can therefore carry stale package-view column ids into this page instead of cleanly falling back to the new defaults.

Suggested fix
-const LEFT_VISIBLE_COLS_KEY = 'requirement-packages.visibleColumns.left.v2'
-const RIGHT_VISIBLE_COLS_KEY = 'requirement-packages.visibleColumns.right.v2'
+const LEFT_VISIBLE_COLS_KEY = 'requirements-specifications.visibleColumns.left.v3'
+const RIGHT_VISIBLE_COLS_KEY = 'requirements-specifications.visibleColumns.right.v3'

As per coding guidelines, "If UI view state is stored in browser storage and its semantics change materially, version the storage key instead of reusing incompatible stored data."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/`[locale]/specifications/[slug]/requirements-specification-detail-client.tsx
around lines 101 - 130, The component currently reuses the old storage key
semantics and accepts any stored array, so stale/incompatible column ids can be
hydrated; update LEFT_VISIBLE_COLS_KEY and RIGHT_VISIBLE_COLS_KEY to a new
version suffix (e.g., change '.v2' → '.v3') and harden readStoredCols: after
JSON.parse, validate that parsed is an array and that every item is a known
RequirementColumnId (compare against the allowed set derived from
DEFAULT_LEFT_COLS, DEFAULT_RIGHT_COLS or an explicit enum/list); if validation
fails (unknown ids, non-string entries, or empty array), return the provided
fallback so the view falls back to new defaults. Ensure the window check and
try/catch remain.
🧹 Nitpick comments (8)
docs/reference-data-and-ai.md (1)

80-110: ⚡ Quick win

Fix internal doc inconsistency: “Package” vs “Specification” taxonomy DAL naming

Section 3 now lists specification-* DAL sources, but the validation variance table and surrounding text still reference package-* DAL filenames and “package workflow gates” (e.g., lines 101-104 and 107-110). This will confuse readers about which implementation actually contains the described behavior.

Proposed doc update
-## 3 — Package Taxonomy Lookups
+## 3 — Specification Taxonomy Lookups
 ...
 - `package-lifecycle-statuses`: returns row count (number).
- - `package-implementation-types`: returns `void`.
- - `package-responsibility-areas`: returns `void`.
+ - `specification-lifecycle-statuses`: returns row count (number).
+ - `specification-implementation-types`: returns `void`.
+ - `specification-responsibility-areas`: returns `void`.
 ...
-This variance is intentional. Lifecycle statuses are
-safety-critical (they determine package workflow gates), while
-implementation types and responsibility areas are informational
+This variance is intentional. Lifecycle statuses are
+safety-critical (they determine specification workflow gates), while
+implementation types and responsibility areas are informational
 taxonomy values.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/reference-data-and-ai.md` around lines 80 - 110, The document uses
`lib/dal/specification-implementation-types.ts`,
`lib/dal/specification-lifecycle-statuses.ts`, and
`lib/dal/specification-responsibility-areas.ts` in the Sources header but still
refers to `package-*` filenames and "package workflow gates" in the validation
table and surrounding text; update all occurrences of
`package-lifecycle-statuses.ts`, `package-implementation-types.ts`, and
`package-responsibility-areas.ts` to the corresponding `specification-...`
filenames and change the phrase "package workflow gates" to "specification
workflow gates" (or another consistent term) so the filenames and explanatory
text consistently reference the specification DALs (ensure changes cover the
table rows, captions, and the two lines describing safety-critical lifecycle
statuses).
cspell.jsonc (2)

37-48: ⚡ Quick win

Remove redundant lowercase duplicates (caseSensitive=false).

Because caseSensitive is false, adding both Kravunderlagslista and kravunderlagslista (and similarly Kravunderlagsdetalj and kravunderlagsdetalj) is likely redundant noise. Consider keeping only one casing variant for each lemma to reduce list churn/merge conflicts.

🛠️ Proposed cleanup
   "Kravunderlagslista",
-  "kravunderlagslista",
   "Kravunderlagsdetalj",
-  "kravunderlagsdetalj",
   "Kravunderlagsdetaljsidan",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cspell.jsonc` around lines 37 - 48, The wordlist contains redundant case
variants because caseSensitive is false; remove the lowercase duplicates so only
one casing variant remains for each lemma (e.g., keep "Kravunderlagslista" and
remove "kravunderlagslista", keep "Kravunderlagsdetalj" and remove
"kravunderlagsdetalj")—update the entries for
"Kravunderlagslista"/"kravunderlagslista" and
"Kravunderlagsdetalj"/"kravunderlagsdetalj" to a single canonical form to reduce
noise and future merge conflicts.

429-435: ⚡ Quick win

Double-check spelling: kravunderlagmedförfattare may be missing “s”.

In the new entries, kravunderlagmedförfattare (line 432) differs from the earlier Kravunderlagsmedförfattare (line 39) by missing the “s” in underlags. If that’s unintentional, cspell may not learn the correct term form you expect.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cspell.jsonc` around lines 429 - 435, The cspell entry
"kravunderlagmedförfattare" is missing the "s" present in the earlier
"Kravunderlagsmedförfattaren"; update the entry in the list to
"kravunderlagsmedförfattare" to match the intended stem (or, if both forms are
valid, add the correctly spelled variant "kravunderlagsmedförfattare" in
addition to any existing capitalized form) so cspell consistently recognizes the
term (look for the tokens "kravunderlagmedförfattare" and
"Kravunderlagsmedförfattaren" to locate the items).
lib/specification-item-status-constants.ts (1)

2-11: ⚡ Quick win

Align JSDoc wording with renamed “specification” domain.

The constants were renamed, but comments still describe “package-item status”.
Update the JSDoc text to avoid domain ambiguity.

Suggested doc-only diff
- * Seed ID for the "Included" / "Inkluderad" package-item status.
- * Every newly added package item starts here.
+ * Seed ID for the "Included" / "Inkluderad" specification-item status.
+ * Every newly added specification item starts here.
...
- * Seed ID for the "Deviated" / "Avviken" package-item status.
- * Only selectable when the package item has an approved deviation.
+ * Seed ID for the "Deviated" / "Avviken" specification-item status.
+ * Only selectable when the specification item has an approved deviation.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/specification-item-status-constants.ts` around lines 2 - 11, Update the
JSDoc comments for the renamed specification domain constants to remove
"package-item" wording and refer to the specification item status domain
instead; edit the comments above DEFAULT_SPECIFICATION_ITEM_STATUS_ID and
DEVIATED_SPECIFICATION_ITEM_STATUS_ID so they describe "specification item
status" (e.g., "Seed ID for the 'Included' specification-item status" and "Seed
ID for the 'Deviated' specification-item status") and keep the existing
explanatory lines about when each status is used.
components/reports/pdf/PdfReportRenderer.tsx (1)

295-297: 🏗️ Heavy lift

Avoid hardcoded label text in the PDF cover renderer.

Line 296 introduces visible copy inline ('Kravunderlag-ID' / 'Specification ID'). Please bind this through translation keys (or pass a prelocalized label via report model) to stay consistent with the localization contract.

As per coding guidelines, "Bind all visible labels to translation keys. Do not hardcode labels in list headers, edit forms, inline detail panes, detail pages, CSV, service output, or MCP HTML".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/reports/pdf/PdfReportRenderer.tsx` around lines 295 - 297, Replace
the hardcoded label string in the PdfReportRenderer Text element with a
localized value: locate the Text with styles.fieldLabel in the PdfReportRenderer
component and bind its content to a translation key (e.g. use the
i18n/translation helper like t('reports.cover.specificationId')) or accept a
prelocalized label from the report model prop and render that instead of the
inline `'Kravunderlag-ID'` / `'Specification ID'`; ensure the new key exists in
the locale files and remove the inline literal so all visible labels are served
via the translation contract.
tests/unit/requirements-specification-items-route.test.ts (1)

39-39: ⚡ Quick win

Add a GET case for the renamed specification route.

This suite now exercises POST/DELETE only, but the handler’s GET path also changed to resolve a specification id and merge deviation counts. A rename/regression there would currently go unnoticed.

As per coding guidelines, "Add or update focused tests for changed DB/admin logic".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/requirements-specification-items-route.test.ts` at line 39, Add a
focused unit test for the GET handler in the specifications items route: import
the GET export from '@/app/api/specifications/[id]/items/route' (in addition to
POST and DELETE) and add a test that calls GET with a request and params
containing the renamed/expected specification id, then assert the response
resolves the correct specification id and returns merged deviation counts
(verify merged counts and any changed fields). Use the same setup/mocks as the
existing POST/DELETE tests (mock DB/admin services) and assert status and JSON
body to catch regressions in the GET path that resolves specification id and
merges deviation counts.
tests/unit/requirements-specification-item-route.test.ts (1)

29-29: ⚡ Quick win

Add PATCH coverage for the renamed item-status payload.

This file pins the renamed GET response, but PATCH also changed from packageItemStatusId to specificationItemStatusId and now resolves against a specification id. A focused PATCH test would lock that contract down.

As per coding guidelines, "Add or update focused tests for changed DB/admin logic".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/requirements-specification-item-route.test.ts` at line 29, The
test currently only imports GET from
'@/app/api/specifications/[id]/items/[itemId]/route' — add a focused unit test
that imports and invokes the PATCH handler from the same route and asserts the
new payload/contract: send a PATCH request body using specificationItemStatusId
(not packageItemStatusId) and target the request against the specification id
(the [id] param) so the handler resolves status against the specification;
update assertions to verify the DB/admin call receives specificationItemStatusId
and the correct specification id was used in the update/resolution.
components/SpecificationLocalRequirementDetailClient.tsx (1)

96-99: ⚡ Quick win

Use the shared default specification-item status constant here.

This gate duplicates the Included status id as 1. If the seeded/default id ever changes, edit/delete will silently flip behavior in the UI while the DAL and tests keep using the shared constant.

Suggested fix
 import { devMarker } from '@/lib/developer-mode-markers'
 import { apiFetch } from '@/lib/http/api-fetch'
+import { DEFAULT_SPECIFICATION_ITEM_STATUS_ID } from '@/lib/specification-item-status-constants'
 ...
-  const INCLUDED_PACKAGE_ITEM_STATUS_ID = 1
   const t = useTranslations('requirement')
 ...
   const canMutateLocalRequirement =
-    requirement.specificationItemStatusId === INCLUDED_PACKAGE_ITEM_STATUS_ID &&
+    requirement.specificationItemStatusId ===
+      DEFAULT_SPECIFICATION_ITEM_STATUS_ID &&
     !hasPendingDeviation

Also applies to: 657-659

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/SpecificationLocalRequirementDetailClient.tsx` around lines 96 -
99, Replace the local hard-coded INCLUDED_PACKAGE_ITEM_STATUS_ID with the shared
default "Included" specification-item status constant: remove the local const
declaration and import the project-wide default Included status constant, then
update all usages of INCLUDED_PACKAGE_ITEM_STATUS_ID (including the other
occurrences mentioned) to reference the shared constant instead.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2016f540-b5c0-4ae2-bacf-f89ea44f53f2

📥 Commits

Reviewing files that changed from the base of the PR and between 9b27eb4 and c2cf261.

📒 Files selected for processing (150)
  • app/[locale]/admin/admin-client.tsx
  • app/[locale]/package-item-statuses/page.tsx
  • app/[locale]/requirement-packages/page.tsx
  • app/[locale]/requirements/[id]/_detail/AddToSpecificationDialog.tsx
  • app/[locale]/requirements/[id]/_detail/RequirementActionRail.tsx
  • app/[locale]/requirements/[id]/_detail/RequirementReportMenu.tsx
  • app/[locale]/requirements/[id]/_detail/SpecificationDeviationRail.tsx
  • app/[locale]/requirements/[id]/_detail/types.ts
  • app/[locale]/requirements/[id]/_detail/use-add-to-specification-dialog.ts
  • app/[locale]/requirements/[id]/_detail/use-deviation-workflow.ts
  • app/[locale]/requirements/[id]/_detail/use-specification-item-context.ts
  • app/[locale]/requirements/[id]/requirement-detail-client.tsx
  • app/[locale]/requirements/requirements-client.tsx
  • app/[locale]/specification-item-statuses/page.tsx
  • app/[locale]/specification-item-statuses/specification-item-statuses-client.tsx
  • app/[locale]/specifications/[slug]/page.tsx
  • app/[locale]/specifications/[slug]/reports/layout.tsx
  • app/[locale]/specifications/[slug]/reports/print/list/page.tsx
  • app/[locale]/specifications/[slug]/requirements-specification-detail-client.tsx
  • app/[locale]/specifications/[slug]/specification-edit-panel.tsx
  • app/[locale]/specifications/implementation-types/implementation-types-client.tsx
  • app/[locale]/specifications/implementation-types/page.tsx
  • app/[locale]/specifications/lifecycle-statuses/lifecycle-statuses-client.tsx
  • app/[locale]/specifications/lifecycle-statuses/page.tsx
  • app/[locale]/specifications/page.tsx
  • app/[locale]/specifications/responsibility-areas/page.tsx
  • app/[locale]/specifications/responsibility-areas/responsibility-areas-client.tsx
  • app/[locale]/specifications/specifications-client.tsx
  • app/api/specification-implementation-types/[id]/route.ts
  • app/api/specification-implementation-types/route.ts
  • app/api/specification-item-deviations/[itemId]/route.ts
  • app/api/specification-item-statuses/[id]/route.ts
  • app/api/specification-item-statuses/route.ts
  • app/api/specification-lifecycle-statuses/[id]/route.ts
  • app/api/specification-lifecycle-statuses/route.ts
  • app/api/specification-local-deviations/[id]/decision/route.ts
  • app/api/specification-local-deviations/[id]/request-review/route.ts
  • app/api/specification-local-deviations/[id]/revert-to-draft/route.ts
  • app/api/specification-local-deviations/[id]/route.ts
  • app/api/specification-responsibility-areas/[id]/route.ts
  • app/api/specification-responsibility-areas/route.ts
  • app/api/specifications/[id]/deviations/route.ts
  • app/api/specifications/[id]/items/[itemId]/route.ts
  • app/api/specifications/[id]/items/route.ts
  • app/api/specifications/[id]/local-requirements/[localRequirementId]/route.ts
  • app/api/specifications/[id]/local-requirements/route.ts
  • app/api/specifications/[id]/needs-references/route.ts
  • app/api/specifications/[id]/report-items/route.ts
  • app/api/specifications/[id]/route.ts
  • app/api/specifications/route.ts
  • components/Navigation.tsx
  • components/RequirementsTable.tsx
  • components/SpecificationLocalRequirementDetailClient.tsx
  • components/SpecificationLocalRequirementForm.tsx
  • components/_requirements-table/SpecificationItemStatusSelect.tsx
  • components/reports/pdf/PdfReportRenderer.tsx
  • components/reports/print/PrintReportRenderer.tsx
  • cspell.jsonc
  • docs/arkitekturbeskrivning-kravhantering.md
  • docs/database-schema.md
  • docs/developer-mode-overlay.md
  • docs/dogfood-seed.md
  • docs/guide/README.md
  • docs/lifecycle-workflow.md
  • docs/mcp-server-contributor-guide.md
  • docs/mcp-server-user-guide.md
  • docs/reference-data-and-ai.md
  • docs/reports.md
  • docs/requirements-ui-behaviour.md
  • lib/dal/deviations.ts
  • lib/dal/package-implementation-types.ts
  • lib/dal/package-responsibility-areas.ts
  • lib/dal/requirements-specifications.ts
  • lib/dal/requirements.ts
  • lib/dal/specification-implementation-types.ts
  • lib/dal/specification-item-statuses.ts
  • lib/dal/specification-lifecycle-statuses.ts
  • lib/dal/specification-responsibility-areas.ts
  • lib/mcp/server.ts
  • lib/reports/data/fetch-deviation.ts
  • lib/reports/data/fetch-specification-items.ts
  • lib/reports/templates/deviation-review-template.ts
  • lib/reports/templates/list-template.ts
  • lib/reports/types.ts
  • lib/requirements/auth.ts
  • lib/requirements/list-view.ts
  • lib/requirements/service.ts
  • lib/requirements/types.ts
  • lib/slug.ts
  • lib/specification-item-status-constants.ts
  • lib/typeorm/entities/deviation.ts
  • lib/typeorm/entities/index.ts
  • lib/typeorm/entities/package-implementation-type.ts
  • lib/typeorm/entities/package-lifecycle-status.ts
  • lib/typeorm/entities/package-local-requirement-norm-reference.ts
  • lib/typeorm/entities/package-local-requirement-usage-scenario.ts
  • lib/typeorm/entities/package-needs-reference.ts
  • lib/typeorm/entities/package-responsibility-area.ts
  • lib/typeorm/entities/requirements-specification-item.ts
  • lib/typeorm/entities/requirements-specification.ts
  • lib/typeorm/entities/specification-implementation-type.ts
  • lib/typeorm/entities/specification-item-status.ts
  • lib/typeorm/entities/specification-lifecycle-status.ts
  • lib/typeorm/entities/specification-local-requirement-deviation.ts
  • lib/typeorm/entities/specification-local-requirement-norm-reference.ts
  • lib/typeorm/entities/specification-local-requirement-usage-scenario.ts
  • lib/typeorm/entities/specification-local-requirement.ts
  • lib/typeorm/entities/specification-needs-reference.ts
  • lib/typeorm/entities/specification-responsibility-area.ts
  • lib/ui-terminology.ts
  • messages/en.json
  • messages/sv.json
  • tests/quality/QUALITY.md
  • tests/quality/functional.test.ts
  • tests/unit/admin-client.test.tsx
  • tests/unit/admin-requirement-columns-route.test.ts
  • tests/unit/deviations-dal.test.ts
  • tests/unit/dogfood-seed.test.ts
  • tests/unit/edit-requirement-client.test.tsx
  • tests/unit/implementation-types-client.test.tsx
  • tests/unit/lifecycle-statuses-client.test.tsx
  • tests/unit/mcp-http.test.ts
  • tests/unit/navigation.test.tsx
  • tests/unit/reference-data-developer-mode.test.tsx
  • tests/unit/requirement-action-rail.test.tsx
  • tests/unit/requirement-detail-client.test.tsx
  • tests/unit/requirement-detail-hooks.test.tsx
  • tests/unit/requirement-list-view.test.ts
  • tests/unit/requirement-report-menu.test.tsx
  • tests/unit/requirements-client.test.tsx
  • tests/unit/requirements-dal.test.ts
  • tests/unit/requirements-service.test.ts
  • tests/unit/requirements-specification-detail-client.test.tsx
  • tests/unit/requirements-specification-item-route.test.ts
  • tests/unit/requirements-specification-items-route.test.ts
  • tests/unit/requirements-specifications-dal.test.ts
  • tests/unit/requirements-table.test.tsx
  • tests/unit/responsibility-areas-client.test.tsx
  • tests/unit/specification-edit-panel.test.tsx
  • tests/unit/specification-item-statuses-client.test.tsx
  • tests/unit/specification-local-deviation-lifecycle-routes.test.ts
  • tests/unit/specification-local-requirement-detail-client.test.tsx
  • tests/unit/specification-report-pages.test.tsx
  • tests/unit/specifications-client.test.tsx
  • tests/unit/taxonomy-routes.test.ts
  • typeorm/migrations/0001_initial_sqlserver.mjs
  • typeorm/migrations/0003_explicit_fk_actions.mjs
  • typeorm/seed-dogfood-build.mjs
  • typeorm/seed-dogfood.mjs
  • typeorm/seed.mjs
💤 Files with no reviewable changes (10)
  • app/[locale]/requirement-packages/page.tsx
  • lib/typeorm/entities/package-local-requirement-usage-scenario.ts
  • lib/typeorm/entities/package-lifecycle-status.ts
  • app/[locale]/package-item-statuses/page.tsx
  • lib/typeorm/entities/package-responsibility-area.ts
  • lib/typeorm/entities/package-needs-reference.ts
  • lib/typeorm/entities/package-local-requirement-norm-reference.ts
  • lib/dal/package-implementation-types.ts
  • lib/dal/package-responsibility-areas.ts
  • lib/typeorm/entities/package-implementation-type.ts

Comment thread app/[locale]/specifications/[slug]/page.tsx Outdated
Comment thread app/[locale]/specifications/page.tsx
Comment thread app/api/specification-item-statuses/route.ts
Comment thread app/api/specification-responsibility-areas/[id]/route.ts
Comment thread app/api/specifications/[id]/items/[itemId]/route.ts
Comment thread app/api/specifications/[id]/items/route.ts Outdated
Comment thread lib/typeorm/entities/specification-needs-reference.ts
Comment thread tests/quality/QUALITY.md Outdated
johlju added 2 commits May 3, 2026 11:33
…tation and codebase

- Updated documentation references to change "package" to "specification" for clarity and consistency.
- Modified code comments and variable names to reflect the new terminology.
- Adjusted test cases to ensure they align with the updated terminology.
- Enhanced SQL queries to include specification-local requirements alongside standard requirements.
- Implemented changes in the UI to display specification-related information correctly.
- Ensured that all relevant tests pass after the terminology updates.
- Changed navigation path from `/sv/requirement-packages/ETJANSTPLATT` to `/sv/specifications/ETJANST-UPP-2026`.
- Updated developer mode trigger from "package reports" to "specification reports".
- Adjusted assertions in tests to match new report terminology.

test: add integration tests for requirements specification detail

- Created `requirements-specification-detail.md` and `requirements-specification-detail.spec.ts` to verify edit functionality and independent scrolling behavior of requirement lists.
- Implemented test cases for opening the edit view and ensuring sticky title bars function correctly.

test: implement integration tests for specifications list

- Added `specifications-list.md` and `specifications-list.spec.ts` to validate rendering of specifications list, filtering functionality, and UI alignment on desktop.

test: add unit tests for specification item statuses data access layer

- Created `specification-item-statuses-dal.test.ts` to test counting and listing linked package items by status.

test: add unit tests for specification local requirement route

- Implemented `specification-local-requirement-route.test.ts` to test deletion of specification-local requirements and error handling.

test: add unit tests for specifications page components

- Created `specifications-page.test.tsx` to ensure correct rendering of specifications metadata and client components.

fix: add cascading delete constraint to specification needs references

- Created migration `0004_specification_needs_reference_cascade.mjs` to enforce cascading deletes on specification needs references.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (8)
docs/dogfood-seed.md (1)

1-123: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Run markdown lint for this docs change before merge.

This PR modifies a markdown file; please run npm run lint:md and include the
result in the PR checks/checklist.

As per coding guidelines, “**/*.md: ... Run npm run lint:md when markdown
docs change”.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/dogfood-seed.md` around lines 1 - 123, Run the markdown linter against
the modified docs/dogfood-seed.md by executing the project script "npm run
lint:md", fix any reported markdown lint errors in docs/dogfood-seed.md (and
related .md files if the linter flags them), commit the fixes, and include the
lint output in the PR checks (paste the command output into the PR description
or attach it as a CI artifact) so the PR shows the lint step passed.
lib/mcp/server.ts (4)

1562-1604: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Tool title and descriptions still use "package" terminology.

The tool ID was renamed to requirements_remove_from_specification but:

  • Line 1563: description says "Identify the package with"
  • Line 1582: requirementIds describes "remove from the package"
  • Line 1604: title is still "Remove Requirements from Package"
Suggested fixes
       description:
-        'Unlink one or more requirements from a requirements specification. The requirements themselves are not deleted. Identify the package with specificationId (numeric) or specificationSlug (e.g. "SAKLYFT-INFOR-Q2").',
+        'Unlink one or more requirements from a requirements specification. The requirements themselves are not deleted. Identify the specification with specificationId (numeric) or specificationSlug (e.g. "SAKLYFT-INFOR-Q2").',
       ...
           requirementIds: z
             .array(z.number().int().positive())
             .min(1)
-            .describe('Numeric requirement IDs to remove from the package.'),
+            .describe('Numeric requirement IDs to remove from the specification.'),
       ...
-      title: 'Remove Requirements from Package',
+      title: 'Remove Requirements from Specification',
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/mcp/server.ts` around lines 1562 - 1604, Update the user-facing strings
to use "specification" instead of the old "package" term: in the route/object
whose id is requirements_remove_from_specification, change the description text
that currently reads "Identify the package with specificationId..." to reference
"Identify the specification with specificationId...", update the requirementIds
.describe(...) text from "remove from the package" to "remove from the
specification", and update the title from "Remove Requirements from Package" to
"Remove Requirements from Specification" (also scan nearby example slug text for
any remaining "package" mentions and replace similarly).

1476-1528: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Tool title and descriptions still use "package" terminology.

The tool ID was renamed to requirements_add_to_specification but:

  • Line 1477: description says "Identify the package with"
  • Line 1503: requirementIds describes "to add to the package"
  • Line 1528: title is still "Add Requirements to Package"
Suggested fixes
       description:
-        'Link one or more requirements to a requirements specification. Requirements must have a published version; those without are skipped and returned in skippedIds. Optionally attach a needs reference text to all added items. Identify the package with specificationId (numeric) or specificationSlug (e.g. "SAKLYFT-INFOR-Q2").',
+        'Link one or more requirements to a requirements specification. Requirements must have a published version; those without are skipped and returned in skippedIds. Optionally attach a needs reference text to all added items. Identify the specification with specificationId (numeric) or specificationSlug (e.g. "SAKLYFT-INFOR-Q2").',
       ...
           requirementIds: z
             .array(z.number().int().positive())
             .min(1)
             .describe(
-              'Numeric requirement IDs (not uniqueId strings) to add to the package.',
+              'Numeric requirement IDs (not uniqueId strings) to add to the specification.',
             ),
       ...
-      title: 'Add Requirements to Package',
+      title: 'Add Requirements to Specification',
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/mcp/server.ts` around lines 1476 - 1528, Update the wording that still
uses "package" to "specification" to match the renamed tool id
requirements_add_to_specification: change the description field text (symbol:
description) that reads "Identify the package with specificationId..." to
reference "specification", update the requirementIds input description (symbol:
requirementIds) from "to add to the package" to "to add to the specification",
and update the title (symbol: title) from "Add Requirements to Package" to "Add
Requirements to Specification" so all user-facing strings align with
requirements_add_to_specification.

1385-1443: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Tool title and description still use "package" terminology.

The tool ID was renamed to requirements_get_specification_items but:

  • Line 1386: description says "Identify the package with specificationId"
  • Line 1443: title is still "Get Package Items"

This creates a mismatch between the tool ID and its title/description.

Suggested fixes
       description:
-        'List requirements (krav) linked to a specific requirements specification, with optional description search. Identify the package with specificationId (numeric) or specificationSlug (e.g. "SAKLYFT-INFOR-Q2") from requirements_list_specifications.',
+        'List requirements (krav) linked to a specific requirements specification, with optional description search. Identify the specification with specificationId (numeric) or specificationSlug (e.g. "SAKLYFT-INFOR-Q2") from requirements_list_specifications.',
       ...
-      title: 'Get Package Items',
+      title: 'Get Specification Items',
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/mcp/server.ts` around lines 1385 - 1443, The tool definition for
requirements_get_specification_items uses "package" in its description and
title; update the description string (near inputSchema.description) to say
"Identify the requirements specification with specificationId..." (or "Identify
the specification by specificationId or specificationSlug") and change the title
from "Get Package Items" to "Get Specification Items" (or "Get Requirements
Specification Items") so wording matches the tool ID and
outputSchema.specificationId; ensure any other user-facing strings in this
object (e.g., the top-level description and title properties) replace "package"
with "specification" for consistency.

1318-1354: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Incomplete terminology rename in tool descriptions and schema.

The tool ID and title were updated to use "specification" but several descriptions still reference "package":

  • Line 1319: description ends with "for each package"
  • Line 1327: nameSearch describes "Swedish and English package names"
  • Line 1335: output schema field is still named packages

Per coding guidelines, MCP tool descriptions and schema field descriptions should be aligned with the tool behavior. MCP clients will see inconsistent terminology.

Suggested terminology fixes
       description:
-        'List all requirements specifications, optionally filtered by name. Returns id, uniqueId (slug), names, item count, responsibility area, and implementation type for each package.',
+        'List all requirements specifications, optionally filtered by name. Returns id, uniqueId (slug), names, item count, responsibility area, and implementation type for each specification.',
       inputSchema: z
         .object({
           locale: z.enum(['en', 'sv']).default('en'),
           nameSearch: z
             .string()
             .optional()
             .describe(
-              'Case-insensitive substring filter applied to both Swedish and English package names.',
+              'Case-insensitive substring filter applied to both Swedish and English specification names.',
             ),
           responseFormat: z.enum(['json', 'markdown']).default('markdown'),
         })
         .strict(),
       outputSchema: z
         .object({
           message: z.string(),
-          packages: z.array(
+          specifications: z.array(

Note: If the output schema field name packages must match the service response shape, consider documenting this in the description or updating the service layer for consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/mcp/server.ts` around lines 1318 - 1354, Update the terminology to
consistently use "specification" instead of "package": edit the description
string (symbol: description) to end with "for each specification", change the
nameSearch.describe text (symbol: nameSearch) to "Case-insensitive substring
filter applied to both Swedish and English specification names", and either
rename the output array field packages to specifications in outputSchema
(symbol: outputSchema -> packages) or, if renaming breaks the service contract,
update the outputSchema description to explicitly document that the field is
named "packages" for compatibility while referring to its items as
specifications; also ensure the title remains "List Requirements
Specifications".
tests/unit/requirements-specification-items-route.test.ts (1)

46-46: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

describe block label still uses old "requirement-packages" terminology.

The suite string should be updated to reflect the renamed route (e.g., 'specifications/[id]/items route'), consistent with the rename intent of this PR.

✏️ Proposed fix
-describe('requirement-packages/[id]/items route', () => {
+describe('specifications/[id]/items route', () => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/requirements-specification-items-route.test.ts` at line 46, Update
the top-level test suite label string used in the describe block currently
written as "requirement-packages/[id]/items route" to the new route name
"specifications/[id]/items route" so the test description matches the renamed
route; locate the describe call (describe('requirement-packages/[id]/items
route', ...) in tests/unit/requirements-specification-items-route.test.ts) and
replace the string, then run the unit tests to confirm no regressions.
app/[locale]/specifications/[slug]/requirements-specification-detail-client.tsx (1)

680-716: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid rolling back the whole list on one PATCH failure.

Line 710 / Line 713 restore the full captured specificationItems snapshot. If two status changes are made back-to-back, a late failure from the first request can wipe out the second successful update as well. Re-fetch the list on failure, or revert only the touched row.

Suggested fix
-      const prev = specificationItems
       // Optimistic update
       setPackageItems(prev =>
         prev.map(item => {
           if (item.itemRef !== itemRef) return item
@@
         const res = await apiFetch(
           `/api/specifications/${pkg.id}/items/${encodeURIComponent(itemRef)}`,
           {
             method: 'PATCH',
             headers: { 'Content-Type': 'application/json' },
             body: JSON.stringify({ specificationItemStatusId: statusId }),
           },
         )
         if (!res.ok) {
-          setPackageItems(prev)
+          await fetchPackageItems({ throwOnError: true })
         }
       } catch {
-        setPackageItems(prev)
+        await fetchPackageItems({ throwOnError: true })
       }
     },
-    [pkg, specificationItemStatuses, specificationItems],
+    [fetchPackageItems, pkg, specificationItemStatuses, specificationItems],
   )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/`[locale]/specifications/[slug]/requirements-specification-detail-client.tsx
around lines 680 - 716, The current optimistic-update in
handleSpecificationItemStatusChange captures the entire specificationItems
snapshot (prev) and restores it on any PATCH failure, which can overwrite
subsequent successful updates; instead on failure either (A) re-fetch the items
list (call the existing fetch/loader that populates specificationItems) to get
authoritative state, or (B) revert only the single touched row by using the prev
snapshot to find the original item for the given itemRef and call
setPackageItems(prevState => prevState.map(i => i.itemRef === itemRef ?
originalItemFromPrev : i)); update the catch and non-ok branches to perform one
of these targeted rollback strategies rather than resetting the whole list.
app/[locale]/specifications/specifications-client.tsx (1)

388-441: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

fetchPackages() at Line 435 is a floating promise — add void.

All other call sites in this file either use void fetchPackages() (lines 384–385) or await fetchPackages() (line 495). The bare call on line 435 is inconsistent and will be flagged by @typescript-eslint/no-floating-promises in a strict-mode TypeScript project.

🛠️ Proposed fix
-      fetchPackages()
+      void fetchPackages()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/`[locale]/specifications/specifications-client.tsx around lines 388 -
441, The handleSubmit function calls fetchPackages() without awaiting or marking
the promise as intentionally ignored, causing a floating promise; change that
call inside handleSubmit (after setForm(resetForm())) to use void
fetchPackages() so linting (`@typescript-eslint/no-floating-promises`) is
satisfied and intent is explicit; update the fetchPackages invocation only (do
not await or alter surrounding state updates like setShowForm, setEditPkg,
setOpenHelp, setSlugEdited, setForm) to preserve existing behavior.
🧹 Nitpick comments (2)
app/[locale]/requirements/[id]/_detail/RequirementActionRail.tsx (1)

7-7: ⚡ Quick win

Consider replacing PackagePlus with a document/specification-oriented icon.

PackagePlus (a box with a plus sign) visually communicates "add to a package," which is now semantically at odds with the renamed "add to specification" action. An icon like FilePlus or BookPlus from lucide-react would better reinforce the new terminology for users.

♻️ Suggested change
 import {
   Archive,
   Check,
   Edit,
-  PackagePlus,
+  FilePlus,
   RotateCcw,
   Share2,
   Trash2,
 } from 'lucide-react'
-  <PackagePlus aria-hidden="true" className="h-4 w-4" />
+  <FilePlus aria-hidden="true" className="h-4 w-4" />

Also applies to: 192-192

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/`[locale]/requirements/[id]/_detail/RequirementActionRail.tsx at line 7,
Replace the PackagePlus icon import and its usages in RequirementActionRail.tsx
with a document-oriented icon (e.g., FilePlus or BookPlus from lucide-react) to
match the "add to specification" action; update the import list to remove
PackagePlus and import FilePlus (or BookPlus) instead, then replace the JSX
occurrences of <PackagePlus .../> (including the other occurrence referenced)
with <FilePlus .../> (or <BookPlus .../>) preserving props and accessibility
attributes so visuals and behavior remain unchanged.
tests/unit/requirements-table.test.tsx (1)

730-788: ⚡ Quick win

Add coverage for the editable specification-item-status branch.

These cases only exercise the read-only renderer. A regression in the renamed onSpecificationItemStatusChange + SpecificationItemStatusSelect path in components/RequirementsTable.tsx (Lines 2372-2390) would still pass this suite.

As per coding guidelines, "When changing visible UI elements, labels, roles, or layout surfaces, update the relevant unit and integration tests."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/requirements-table.test.tsx` around lines 730 - 788, Tests only
cover the read-only status renderer; add a unit that exercises the editable
branch by rendering RequirementsTable with the specification-item-status column
editable, providing a spy for onSpecificationItemStatusChange and asserting that
SpecificationItemStatusSelect is rendered and that selecting/changing a status
calls onSpecificationItemStatusChange with the expected args; specifically
target the renamed handler onSpecificationItemStatusChange and the
SpecificationItemStatusSelect component path in RequirementsTable to prevent
regressions in lines around the previous 2372-2390 area.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@app/`[locale]/specifications/[slug]/requirements-specification-detail-client.tsx:
- Around line 1001-1002: Replace the hardcoded English filename assigned to
a.download by resolving it from your translations instead of embedding text;
update the assignment that sets a.download (currently using locale === 'sv' ?
'kravunderlag.csv' : 'requirement-package.csv') to call the app's i18n lookup
(e.g., useTranslations/getDictionary or the existing translation hook) and use a
new translation key such as "specification.downloadFilename" with
language-specific values (sv: "kravunderlag.csv", en: "specification.csv");
ensure you reference the same translation API used elsewhere in this component
so visible labels (a.download) are not hardcoded.

In `@docs/dogfood-seed.md`:
- Around line 26-37: Reformat the ID ranges markdown table (the block starting
with the header "| Entity | Base IDs | Dogfood IDs |") to MD060 compact style by
removing the padding spaces around cell content and pipes (e.g., change "|
`owners`                            | 1–3      | 1001–1005                |" to
"|`owners`|1–3|1001–1005|"), keep the header and separator row intact (using the
same number of columns and backticks for identifiers) and preserve all cell
text/IDs unchanged except for whitespace so the table becomes unpadded/compact.

In `@lib/dal/specification-item-statuses.ts`:
- Around line 197-201: The deleteSpecificationItemStatus function currently
deletes any id; protect seeded system statuses by checking if id equals
DEFAULT_SPECIFICATION_ITEM_STATUS_ID or DEVIATED_SPECIFICATION_ITEM_STATUS_ID
and refuse to delete them (throw a descriptive error or return without
deleting). Modify deleteSpecificationItemStatus (in
lib/dal/specification-item-statuses.ts) to perform this guard before calling
db.getRepository(specificationItemStatusEntity).delete(id) so seeded statuses
cannot be removed.

In `@tests/quality/functional.test.ts`:
- Line 785: Multiple it() blocks share the exact title "Scenario 12: concurrent
archiving attempts are atomic and strictly targeted", preventing vitest -t from
selecting individual sub-scenarios; update each it() description in
tests/quality/functional.test.ts (the four it() occurrences that test
initiateArchiving, approveArchiving, approve vs cancel, and manual state
manipulation) to have unique, verbatim titles such as "Scenario 12a: concurrent
initiateArchiving attempts are atomic and strictly targeted", "Scenario 12b:
concurrent approveArchiving attempts are atomic and strictly targeted",
"Scenario 12c: concurrent approveArchiving vs cancelArchiving are atomic and
strictly targeted", and "Scenario 12d: strict-target behavior with manual state
manipulation", respectively; ensure the new titles match any corresponding
headings in QUALITY.md (or update QUALITY.md to reflect 12a–12d) so vitest -t
can target each scenario individually.

In `@tests/unit/taxonomy-routes.test.ts`:
- Around line 125-133: The test imports for route handlers (GET, POST, PUT,
DELETE) from '@/app/api/catalog/specification-item-statuses/route' and
'@/app/api/catalog/specification-item-statuses/[id]/route' are failing TS2307
because those named exports don't exist at those paths; either add and export
the corresponding handler functions (GET, POST in
specification-item-statuses/route and GET, PUT, DELETE in
specification-item-statuses/[id]/route) with the exact names used in the test,
or update the test imports to point to the actual module that exports these
handlers—ensure the exported function names match the test (GET, POST, PUT,
DELETE) so TypeScript can resolve them.

---

Outside diff comments:
In
`@app/`[locale]/specifications/[slug]/requirements-specification-detail-client.tsx:
- Around line 680-716: The current optimistic-update in
handleSpecificationItemStatusChange captures the entire specificationItems
snapshot (prev) and restores it on any PATCH failure, which can overwrite
subsequent successful updates; instead on failure either (A) re-fetch the items
list (call the existing fetch/loader that populates specificationItems) to get
authoritative state, or (B) revert only the single touched row by using the prev
snapshot to find the original item for the given itemRef and call
setPackageItems(prevState => prevState.map(i => i.itemRef === itemRef ?
originalItemFromPrev : i)); update the catch and non-ok branches to perform one
of these targeted rollback strategies rather than resetting the whole list.

In `@app/`[locale]/specifications/specifications-client.tsx:
- Around line 388-441: The handleSubmit function calls fetchPackages() without
awaiting or marking the promise as intentionally ignored, causing a floating
promise; change that call inside handleSubmit (after setForm(resetForm())) to
use void fetchPackages() so linting (`@typescript-eslint/no-floating-promises`) is
satisfied and intent is explicit; update the fetchPackages invocation only (do
not await or alter surrounding state updates like setShowForm, setEditPkg,
setOpenHelp, setSlugEdited, setForm) to preserve existing behavior.

In `@docs/dogfood-seed.md`:
- Around line 1-123: Run the markdown linter against the modified
docs/dogfood-seed.md by executing the project script "npm run lint:md", fix any
reported markdown lint errors in docs/dogfood-seed.md (and related .md files if
the linter flags them), commit the fixes, and include the lint output in the PR
checks (paste the command output into the PR description or attach it as a CI
artifact) so the PR shows the lint step passed.

In `@lib/mcp/server.ts`:
- Around line 1562-1604: Update the user-facing strings to use "specification"
instead of the old "package" term: in the route/object whose id is
requirements_remove_from_specification, change the description text that
currently reads "Identify the package with specificationId..." to reference
"Identify the specification with specificationId...", update the requirementIds
.describe(...) text from "remove from the package" to "remove from the
specification", and update the title from "Remove Requirements from Package" to
"Remove Requirements from Specification" (also scan nearby example slug text for
any remaining "package" mentions and replace similarly).
- Around line 1476-1528: Update the wording that still uses "package" to
"specification" to match the renamed tool id requirements_add_to_specification:
change the description field text (symbol: description) that reads "Identify the
package with specificationId..." to reference "specification", update the
requirementIds input description (symbol: requirementIds) from "to add to the
package" to "to add to the specification", and update the title (symbol: title)
from "Add Requirements to Package" to "Add Requirements to Specification" so all
user-facing strings align with requirements_add_to_specification.
- Around line 1385-1443: The tool definition for
requirements_get_specification_items uses "package" in its description and
title; update the description string (near inputSchema.description) to say
"Identify the requirements specification with specificationId..." (or "Identify
the specification by specificationId or specificationSlug") and change the title
from "Get Package Items" to "Get Specification Items" (or "Get Requirements
Specification Items") so wording matches the tool ID and
outputSchema.specificationId; ensure any other user-facing strings in this
object (e.g., the top-level description and title properties) replace "package"
with "specification" for consistency.
- Around line 1318-1354: Update the terminology to consistently use
"specification" instead of "package": edit the description string (symbol:
description) to end with "for each specification", change the
nameSearch.describe text (symbol: nameSearch) to "Case-insensitive substring
filter applied to both Swedish and English specification names", and either
rename the output array field packages to specifications in outputSchema
(symbol: outputSchema -> packages) or, if renaming breaks the service contract,
update the outputSchema description to explicitly document that the field is
named "packages" for compatibility while referring to its items as
specifications; also ensure the title remains "List Requirements
Specifications".

In `@tests/unit/requirements-specification-items-route.test.ts`:
- Line 46: Update the top-level test suite label string used in the describe
block currently written as "requirement-packages/[id]/items route" to the new
route name "specifications/[id]/items route" so the test description matches the
renamed route; locate the describe call
(describe('requirement-packages/[id]/items route', ...) in
tests/unit/requirements-specification-items-route.test.ts) and replace the
string, then run the unit tests to confirm no regressions.

---

Nitpick comments:
In `@app/`[locale]/requirements/[id]/_detail/RequirementActionRail.tsx:
- Line 7: Replace the PackagePlus icon import and its usages in
RequirementActionRail.tsx with a document-oriented icon (e.g., FilePlus or
BookPlus from lucide-react) to match the "add to specification" action; update
the import list to remove PackagePlus and import FilePlus (or BookPlus) instead,
then replace the JSX occurrences of <PackagePlus .../> (including the other
occurrence referenced) with <FilePlus .../> (or <BookPlus .../>) preserving
props and accessibility attributes so visuals and behavior remain unchanged.

In `@tests/unit/requirements-table.test.tsx`:
- Around line 730-788: Tests only cover the read-only status renderer; add a
unit that exercises the editable branch by rendering RequirementsTable with the
specification-item-status column editable, providing a spy for
onSpecificationItemStatusChange and asserting that SpecificationItemStatusSelect
is rendered and that selecting/changing a status calls
onSpecificationItemStatusChange with the expected args; specifically target the
renamed handler onSpecificationItemStatusChange and the
SpecificationItemStatusSelect component path in RequirementsTable to prevent
regressions in lines around the previous 2372-2390 area.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3bb3ccf6-08d6-4893-b4b5-91c1782b7cd2

📥 Commits

Reviewing files that changed from the base of the PR and between c2cf261 and 336cdc3.

📒 Files selected for processing (36)
  • app/[locale]/requirements/[id]/_detail/RequirementActionRail.tsx
  • app/[locale]/specification-item-statuses/specification-item-statuses-client.tsx
  • app/[locale]/specifications/[slug]/requirements-specification-detail-client.tsx
  • app/[locale]/specifications/[slug]/specification-edit-panel.tsx
  • app/[locale]/specifications/specifications-client.tsx
  • app/api/specification-responsibility-areas/[id]/route.ts
  • app/api/specifications/[id]/items/[itemId]/route.ts
  • app/api/specifications/[id]/items/route.ts
  • app/api/specifications/[id]/local-requirements/[localRequirementId]/route.ts
  • components/RequirementsTable.tsx
  • components/SpecificationLocalRequirementDetailClient.tsx
  • components/reports/pdf/PdfReportRenderer.tsx
  • cspell.jsonc
  • docs/database-schema.md
  • docs/developer-mode-overlay.md
  • docs/dogfood-seed.md
  • docs/reference-data-and-ai.md
  • docs/reports.md
  • lib/dal/specification-item-statuses.ts
  • lib/mcp/server.ts
  • lib/requirements/service.ts
  • lib/specification-item-status-constants.ts
  • lib/typeorm/entities/specification-needs-reference.ts
  • tests/quality/QUALITY.md
  • tests/quality/functional.test.ts
  • tests/unit/requirement-detail-client.test.tsx
  • tests/unit/requirements-service.test.ts
  • tests/unit/requirements-specification-detail-client.test.tsx
  • tests/unit/requirements-specification-item-route.test.ts
  • tests/unit/requirements-specification-items-route.test.ts
  • tests/unit/requirements-table.test.tsx
  • tests/unit/specification-edit-panel.test.tsx
  • tests/unit/specification-item-statuses-client.test.tsx
  • tests/unit/specifications-client.test.tsx
  • tests/unit/taxonomy-routes.test.ts
  • typeorm/seed.mjs
✅ Files skipped from review due to trivial changes (6)
  • lib/specification-item-status-constants.ts
  • docs/developer-mode-overlay.md
  • docs/reports.md
  • docs/database-schema.md
  • tests/unit/requirements-service.test.ts
  • tests/quality/QUALITY.md
🚧 Files skipped from review as they are similar to previous changes (14)
  • lib/typeorm/entities/specification-needs-reference.ts
  • app/api/specifications/[id]/local-requirements/[localRequirementId]/route.ts
  • tests/unit/specification-item-statuses-client.test.tsx
  • tests/unit/requirements-specification-item-route.test.ts
  • app/api/specifications/[id]/items/route.ts
  • cspell.jsonc
  • app/api/specification-responsibility-areas/[id]/route.ts
  • tests/unit/requirements-specification-detail-client.test.tsx
  • tests/unit/specification-edit-panel.test.tsx
  • app/api/specifications/[id]/items/[itemId]/route.ts
  • components/SpecificationLocalRequirementDetailClient.tsx
  • app/[locale]/specifications/[slug]/specification-edit-panel.tsx
  • lib/requirements/service.ts
  • tests/unit/requirement-detail-client.test.tsx

Comment thread app/[locale]/specifications/[slug]/requirements-specification-detail-client.tsx Outdated
Comment thread docs/dogfood-seed.md Outdated
Comment thread lib/dal/specification-item-statuses.ts
Comment thread tests/quality/functional.test.ts Outdated
Comment thread tests/unit/taxonomy-routes.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
.github/skills/run-spec-audit/references/integration-contracts.md (1)

65-77: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Package Detail contract appears to document a non-existent field.

Line 76 lists localRequirementNextSequence, but the current package-detail DAL mapping (lib/dal/requirements-specifications.ts:433-457 and :379-430) does not expose that field. This makes the contract table inaccurate as audit ground truth.

Proposed fix
-| `localRequirementNextSequence` | `number` | Next local seq |

If the API should return it, implement and map it in app/api/specifications/[id]/route.ts and DAL, then keep the row.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/skills/run-spec-audit/references/integration-contracts.md around
lines 65 - 77, The contract lists a non-existent field
localRequirementNextSequence; either remove that row from the contract or
implement and surface the field: update the DAL in
lib/dal/requirements-specifications.ts (the package-detail assembly functions)
to compute localRequirementNextSequence (e.g., max local requirement sequence
for the package + 1) and include it on the package DTO, then update
app/api/specifications/[id]/route.ts to map the returned DAL package object to
include localRequirementNextSequence in the JSON response so the REST contract
matches the actual API output.
tests/integration/specifications-list.spec.ts (1)

9-12: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update stale test describe and test names to match renamed domain.

The outer describe block (Line 9) still says "Requirement packages list filter" and the inner test (Line 12) still says "filters the table by package name". Both should reflect the specifications terminology; failing CI output will show misleading labels.

✏️ Proposed fix
-  test.describe(`Requirement packages list filter — ${viewport.name} (${viewport.width}×${viewport.height})`, () => {
+  test.describe(`Requirements specifications list filter — ${viewport.name} (${viewport.width}×${viewport.height})`, () => {
     test.use({ viewport: { width: viewport.width, height: viewport.height } })

-    test('filters the table by package name and clears the search', async ({
+    test('filters the table by specification name and clears the search', async ({
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/integration/specifications-list.spec.ts` around lines 9 - 12, Update
the stale human-readable test labels: change the test.describe string
"Requirement packages list filter — ${viewport.name} (...)" to use the
specifications domain wording (e.g., "Specifications list filter —
${viewport.name} (...)"), and rename the inner test title passed to test(...)
from "filters the table by package name and clears the search" to match the
specifications terminology (e.g., "filters the table by specification name and
clears the search"); modify only the description strings in the
test.describe(...) and test(...) calls so CI output and test reports reflect the
renamed domain.
tests/integration/developer-mode-overlay.md (1)

9-9: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Incomplete rename: stale "package" terminology in flowchart, section headings, and intro

The following locations still use old "package" terminology after the rename to "specification reports":

Location Stale text Expected
Line 9 package-context report controls specification report controls
Line 26 C -- package reports --> L[...] C -- specification reports --> L[...]
Lines 27–29 Hover package report control, Assert package report chip specification report control/chip
Line 134 ## exposes package report controls in developer mode ## exposes specification report controls in developer mode
Lines 136, 143 ### Purpose: Package Report Reference / ### Step-by-Step Flow: Package Report Reference Specification Report Reference

Also applies to: 26-29, 134-143

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/integration/developer-mode-overlay.md` at line 9, Replace all remaining
uses of "package" terminology with "specification" in this markdown: change
"package-context report controls" to "specification report controls", update the
flowchart arrow label `C -- package reports --> L[...]` to `C -- specification
reports --> L[...]`, rename occurrences "Hover package report control" and
"Assert package report chip" to "Hover specification report control" and "Assert
specification report chip", and update the section heading `## exposes package
report controls in developer mode` and the subheadings `### Purpose: Package
Report Reference` / `### Step-by-Step Flow: Package Report Reference` to use
"Specification Report Reference"; search for the listed phrases to ensure no
stale instances remain.
🧹 Nitpick comments (4)
.github/skills/run-spec-audit/references/integration-contracts.md (1)

65-67: ⚡ Quick win

Use “Specification” terminology in section titles for consistency.

Line 65 and Line 85 still use “Package …” while the routes and fields are specification-scoped. Renaming these headers improves clarity and aligns with this PR’s stated terminology migration.

Proposed fix
-## REST: Package Detail `/api/specifications/[id]`
+## REST: Specification Detail `/api/specifications/[id]`

-## REST: Package Items `/api/specifications/[id]/items`
+## REST: Specification Items `/api/specifications/[id]/items`

Also applies to: 85-87

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/skills/run-spec-audit/references/integration-contracts.md around
lines 65 - 67, Update the section headers to use "Specification" terminology for
consistency: rename the header "REST: Package Detail `/api/specifications/[id]`"
to "REST: Specification Detail `/api/specifications/[id]`" (and likewise change
the header at lines 85–87 from "Package ..." to "Specification ..." to match the
route and fields). Locate these markdown headings in integration-contracts.md
and replace "Package" with "Specification" so the titles align with the
`app/api/specifications/[id]/route.ts` and the overall terminology migration.
tests/unit/specification-local-requirement-route.test.ts (1)

31-69: ⚡ Quick win

Expand coverage to the remaining response branches.

The entire mock infrastructure is already in place, but only the 500 error path is exercised. The route handler (Context snippet 1) has four other reachable branches that are currently untested:

Scenario Expected response
localRequirementId is non-numeric / < 1 400 { error: 'Invalid localRequirementId' }
resolvePackageId returns null (unknown slug) 404 { error: 'Not found' }
deleteSpecificationLocalRequirement resolves false (row missing) 404 { error: 'Not found' }
deleteSpecificationLocalRequirement resolves true 200 { ok: true }

Adding these cases is low-cost because mockDb, makeParams, and all mock stubs are already wired up.

🧪 Suggested additional test cases
+  it('returns 400 for a non-integer localRequirementId', async () => {
+    const response = await DELETE(
+      new NextRequest('http://localhost/api/specifications/pkg/local-requirements/abc'),
+      makeParams('pkg', 'abc'),
+    )
+    expect(response.status).toBe(400)
+    await expect(response.json()).resolves.toEqual({ error: 'Invalid localRequirementId' })
+  })
+
+  it('returns 404 when the specification slug is not found', async () => {
+    mocks.getPackageBySlug.mockResolvedValue(null)
+    const response = await DELETE(
+      new NextRequest('http://localhost/api/specifications/unknown/local-requirements/41'),
+      makeParams('unknown', '41'),
+    )
+    expect(response.status).toBe(404)
+    await expect(response.json()).resolves.toEqual({ error: 'Not found' })
+  })
+
+  it('returns 404 when the local requirement row does not exist', async () => {
+    mocks.deleteSpecificationLocalRequirement.mockResolvedValue(false)
+    const response = await DELETE(
+      new NextRequest('http://localhost/api/specifications/pkg/local-requirements/41'),
+      makeParams('pkg', '41'),
+    )
+    expect(response.status).toBe(404)
+    await expect(response.json()).resolves.toEqual({ error: 'Not found' })
+  })
+
+  it('returns 200 on successful deletion', async () => {
+    mocks.deleteSpecificationLocalRequirement.mockResolvedValue(true)
+    const response = await DELETE(
+      new NextRequest('http://localhost/api/specifications/pkg/local-requirements/41'),
+      makeParams('pkg', '41'),
+    )
+    expect(response.status).toBe(200)
+    await expect(response.json()).resolves.toEqual({ ok: true })
+  })

As per coding guidelines, test files matching **/*.test.{mjs,js,ts} should "Add or update focused tests for changed DB/admin logic."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/unit/specification-local-requirement-route.test.ts` around lines 31 -
69, Add unit tests for the remaining response branches of the DELETE route:
create separate it blocks that call the DELETE handler (same call pattern as the
existing test using NextRequest and makeParams) and assert the expected status
and JSON for each case—(1) non-numeric or <1 localRequirementId: set
makeParams('pkg','0' or 'abc') and expect 400 with { error: 'Invalid
localRequirementId' }, (2) resolvePackageId returns null/unknown slug: mock
getPackageBySlug (or resolvePackageId) to return null and expect 404 with {
error: 'Not found' }, (3) deleteSpecificationLocalRequirement resolves false:
mock it to resolve false and expect 404 with { error: 'Not found' }, and (4)
resolves true: mock it to resolve true and expect 200 with { ok: true }; reuse
mockDb, makeParams, and existing mocks, and mirror the pattern used in the
existing 500 test (including spying on console.error only where needed).
app/api/catalog/specification-item-statuses/route.ts (2)

4-8: ⚡ Quick win

QUALITY.md classification required for specification-item-status DAL switch.

Switching GET/POST from package-item-status DAL to specification-item-status DAL changes which database tables are queried — this is outward-facing behavior change. Per coding guidelines for lib/dal/**/*.ts and app/api/**/route.ts, this must be classified:

  • If this is a pure refactor with no behavior change → no update needed.
  • If it's new/changed outward behavior → add/update the matching Fitness Scenario in tests/quality/QUALITY.md and tests/quality/functional.test.ts.

As per coding guidelines: "Read tests/quality/QUALITY.md before changing lifecycle, package-item status, MCP tools, report columns, or admin-default behavior" and classify the change accordingly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/catalog/specification-item-statuses/route.ts` around lines 4 - 8, You
switched GET/POST handlers to use createSpecificationItemStatus and
listSpecificationItemStatuses (and DEVIATED_SPECIFICATION_ITEM_STATUS_ID), which
may change outward-facing DB behavior; determine whether this is purely a
refactor or a behavior change and update tests/quality accordingly: if behavior
changed, add or update the corresponding Fitness Scenario entry in QUALITY.md
and add/adjust the matching test in tests/quality/functional.test.ts to cover
the new specification-item-status table behavior (include the new status id
DEVIATED_SPECIFICATION_ITEM_STATUS_ID in test fixtures/assertions); if it is
purely internal refactor, add a short note in QUALITY.md marking it as
refactor-only. Ensure the modifications reference createSpecificationItemStatus,
listSpecificationItemStatuses, and DEVIATED_SPECIFICATION_ITEM_STATUS_ID so
reviewers can verify coverage.

3-3: Naming inconsistency: countLinkedPackageItems is semantically correct but misleadingly named.

The function countLinkedPackageItems (lines 3, 14) correctly queries requirements_specification_items and specification_local_requirements by specification_item_status_id, not package-item tables. The logic is sound—no data correctness issue exists. However, the function name suggests it counts package items, creating confusion in a specification-item-status context. Consider renaming to countLinkedSpecificationItems for semantic clarity.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/catalog/specification-item-statuses/route.ts` at line 3, Rename the
function countLinkedPackageItems to countLinkedSpecificationItems to match its
behavior (it queries requirements_specification_items and
specification_local_requirements by specification_item_status_id); update the
function declaration, all references/imports/exports (e.g., any uses within
route handlers or tests) to the new name, and update any JSDoc/comments to
reflect "specification items" instead of "package items" so the symbol and
documentation are semantically consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/integration/developer-mode-overlay.md`:
- Around line 144-151: Docs and test disagree: the markdown step currently
expects "report print button: package reports" but
developer-mode-overlay.spec.ts asserts 'report print button: specification
reports'; update the documentation to match the test by changing the chip
assertion in tests/integration/developer-mode-overlay.md (the step that
references data-developer-mode-value and the chip text) to "report print button:
specification reports" so it aligns with the assertion in
developer-mode-overlay.spec.ts and the data-developer-mode-value="specification
reports" selector.

In `@tests/unit/specifications-page.test.tsx`:
- Around line 35-50: Rename the exported async component function
KravunderlagDetailPage to RequirementsSpecificationDetailPage in the page module
and update the test to import and call RequirementsSpecificationDetailPage (also
update the it description string to mention
RequirementsSpecificationDetailClient instead of the old Swedish name); ensure
the test's destructured variable and the params call remain the same except for
the new function name so the rendered output still contains the slug value used
in the expectation.

---

Outside diff comments:
In @.github/skills/run-spec-audit/references/integration-contracts.md:
- Around line 65-77: The contract lists a non-existent field
localRequirementNextSequence; either remove that row from the contract or
implement and surface the field: update the DAL in
lib/dal/requirements-specifications.ts (the package-detail assembly functions)
to compute localRequirementNextSequence (e.g., max local requirement sequence
for the package + 1) and include it on the package DTO, then update
app/api/specifications/[id]/route.ts to map the returned DAL package object to
include localRequirementNextSequence in the JSON response so the REST contract
matches the actual API output.

In `@tests/integration/developer-mode-overlay.md`:
- Line 9: Replace all remaining uses of "package" terminology with
"specification" in this markdown: change "package-context report controls" to
"specification report controls", update the flowchart arrow label `C -- package
reports --> L[...]` to `C -- specification reports --> L[...]`, rename
occurrences "Hover package report control" and "Assert package report chip" to
"Hover specification report control" and "Assert specification report chip", and
update the section heading `## exposes package report controls in developer
mode` and the subheadings `### Purpose: Package Report Reference` / `###
Step-by-Step Flow: Package Report Reference` to use "Specification Report
Reference"; search for the listed phrases to ensure no stale instances remain.

In `@tests/integration/specifications-list.spec.ts`:
- Around line 9-12: Update the stale human-readable test labels: change the
test.describe string "Requirement packages list filter — ${viewport.name} (...)"
to use the specifications domain wording (e.g., "Specifications list filter —
${viewport.name} (...)"), and rename the inner test title passed to test(...)
from "filters the table by package name and clears the search" to match the
specifications terminology (e.g., "filters the table by specification name and
clears the search"); modify only the description strings in the
test.describe(...) and test(...) calls so CI output and test reports reflect the
renamed domain.

---

Nitpick comments:
In @.github/skills/run-spec-audit/references/integration-contracts.md:
- Around line 65-67: Update the section headers to use "Specification"
terminology for consistency: rename the header "REST: Package Detail
`/api/specifications/[id]`" to "REST: Specification Detail
`/api/specifications/[id]`" (and likewise change the header at lines 85–87 from
"Package ..." to "Specification ..." to match the route and fields). Locate
these markdown headings in integration-contracts.md and replace "Package" with
"Specification" so the titles align with the
`app/api/specifications/[id]/route.ts` and the overall terminology migration.

In `@app/api/catalog/specification-item-statuses/route.ts`:
- Around line 4-8: You switched GET/POST handlers to use
createSpecificationItemStatus and listSpecificationItemStatuses (and
DEVIATED_SPECIFICATION_ITEM_STATUS_ID), which may change outward-facing DB
behavior; determine whether this is purely a refactor or a behavior change and
update tests/quality accordingly: if behavior changed, add or update the
corresponding Fitness Scenario entry in QUALITY.md and add/adjust the matching
test in tests/quality/functional.test.ts to cover the new
specification-item-status table behavior (include the new status id
DEVIATED_SPECIFICATION_ITEM_STATUS_ID in test fixtures/assertions); if it is
purely internal refactor, add a short note in QUALITY.md marking it as
refactor-only. Ensure the modifications reference createSpecificationItemStatus,
listSpecificationItemStatuses, and DEVIATED_SPECIFICATION_ITEM_STATUS_ID so
reviewers can verify coverage.
- Line 3: Rename the function countLinkedPackageItems to
countLinkedSpecificationItems to match its behavior (it queries
requirements_specification_items and specification_local_requirements by
specification_item_status_id); update the function declaration, all
references/imports/exports (e.g., any uses within route handlers or tests) to
the new name, and update any JSDoc/comments to reflect "specification items"
instead of "package items" so the symbol and documentation are semantically
consistent.

In `@tests/unit/specification-local-requirement-route.test.ts`:
- Around line 31-69: Add unit tests for the remaining response branches of the
DELETE route: create separate it blocks that call the DELETE handler (same call
pattern as the existing test using NextRequest and makeParams) and assert the
expected status and JSON for each case—(1) non-numeric or <1 localRequirementId:
set makeParams('pkg','0' or 'abc') and expect 400 with { error: 'Invalid
localRequirementId' }, (2) resolvePackageId returns null/unknown slug: mock
getPackageBySlug (or resolvePackageId) to return null and expect 404 with {
error: 'Not found' }, (3) deleteSpecificationLocalRequirement resolves false:
mock it to resolve false and expect 404 with { error: 'Not found' }, and (4)
resolves true: mock it to resolve true and expect 200 with { ok: true }; reuse
mockDb, makeParams, and existing mocks, and mirror the pattern used in the
existing 500 test (including spying on console.error only where needed).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e77f73bd-dd27-46b4-9329-e98b681ab46a

📥 Commits

Reviewing files that changed from the base of the PR and between 336cdc3 and af74721.

📒 Files selected for processing (18)
  • .github/instructions/next-runtime.instructions.md
  • .github/skills/run-spec-audit/references/integration-contracts.md
  • .github/skills/run-spec-audit/references/scrutiny-areas.md
  • .github/skills/update-guide-spec/SKILL.md
  • .markdownlint-cli2.jsonc
  • app/api/catalog/specification-item-statuses/[id]/route.ts
  • app/api/catalog/specification-item-statuses/route.ts
  • tests/guide/generate-guide.spec.ts
  • tests/integration/developer-mode-overlay.md
  • tests/integration/developer-mode-overlay.spec.ts
  • tests/integration/requirements-specification-detail.md
  • tests/integration/requirements-specification-detail.spec.ts
  • tests/integration/specifications-list.md
  • tests/integration/specifications-list.spec.ts
  • tests/unit/specification-item-statuses-dal.test.ts
  • tests/unit/specification-local-requirement-route.test.ts
  • tests/unit/specifications-page.test.tsx
  • typeorm/migrations/0004_specification_needs_reference_cascade.mjs
✅ Files skipped from review due to trivial changes (4)
  • .markdownlint-cli2.jsonc
  • tests/unit/specification-item-statuses-dal.test.ts
  • .github/instructions/next-runtime.instructions.md
  • tests/integration/requirements-specification-detail.md

Comment thread tests/integration/developer-mode-overlay.md Outdated
Comment thread tests/unit/specifications-page.test.tsx Outdated
johlju added 3 commits May 3, 2026 13:40
…d files

- Updated test files to replace instances of "package" with "specification" for clarity and consistency.
- Adjusted seed files to reflect the change from packages to specifications, including updates to data structures and comments.
- Ensured all related mock implementations and API responses are aligned with the new terminology.
@johlju

johlju commented May 3, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

…nd documentation

Co-authored-by: Copilot <copilot@github.com>
@johlju

johlju commented May 3, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
tests/guide/generate-guide.spec.ts (1)

1222-1233: ⚠️ Potential issue | 🟠 Major

Fail fast when the underlag panel doesn't load or has no rows.

Line 1225 swallows the visibility timeout, and the rowCount > 0 guard then skips the entire deviation workflow silently. For a guide generation test, this can produce an incomplete guide without failing the test, masking regressions in selectors or test data setup.

💡 Suggested fix
-      await page
-        .locator('[data-specification-detail-list-panel="items"]')
-        .waitFor({ state: 'visible', timeout: 15_000 })
-        .catch(() => {})
+      await expect(
+        page.locator('[data-specification-detail-list-panel="items"]'),
+      ).toBeVisible({ timeout: 15_000 })

       // Scope to the left panel (items in specification) — right panel is "available" requirements
       const allRows = page.locator(
         '[data-specification-detail-list-panel="items"] tbody tr',
       )
       const rowCount = await allRows.count()
+      expect(
+        rowCount,
+        'Expected seeded requirements in specification ETJANST-UPP-2026',
+      ).toBeGreaterThan(0)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/guide/generate-guide.spec.ts` around lines 1222 - 1233, The test
swallows the waitFor timeout and then silently skips the deviation workflow when
no rows are present; update the block around
page.locator('[data-specification-detail-list-panel="items"]').waitFor(...) and
the subsequent allRows/rowCount check so that the waitFor error is not caught
(or rethrow the error) and add an explicit assertion that rowCount > 0 (throwing
a clear error message referencing the specification panel) instead of simply
skipping when rowCount is 0; reference the page.locator call, the allRows
locator, and the rowCount variable when making these changes.
tests/quality/QUALITY.md (1)

85-127: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Re-verify the requirements.ts line anchors in these scenarios.

Scenario 2 now points reviewers at lib/dal/requirements.ts:1107-1129, and Scenario 3 points at 1452-1468, but the current archiving/publishing logic in the provided file lives much earlier (initiateArchiving() around Lines 960-966 and transitionStatus() around Lines 1197-1207). Leaving stale anchors here makes the audit instructions point at the wrong code.

As per coding guidelines, "For changes to existing covered invariants: update the matching Fitness Scenario wording, re-verify cited line ranges, and update test case."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/quality/QUALITY.md` around lines 85 - 127, Update the outdated line
anchors and tests to point at the current locations of the archiving/publishing
logic: locate initiateArchiving() and transitionStatus() in
lib/dal/requirements.ts (they now live earlier than the anchors in QUALITY.md)
and correct the quoted line ranges in the Scenario 2 and Scenario 3 sections;
also re-run and update the functional test selector/test case wording if
necessary so the verification commands and test name match the updated code
positions and behavior.
app/api/specifications/route.ts (1)

15-34: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject malformed and ambiguous specification payloads before insert.

This handler still 500s on malformed JSON, never validates name, and accepts digit-only uniqueId values even though sibling /specifications/[id] routes treat /^\d+$/ as a numeric record id first. That makes a slug like "123" ambiguous or unreachable once created.

Suggested hardening
 export async function POST(request: NextRequest) {
   const db = await getRequestSqlServerDataSource()
-  const body = (await request.json()) as Parameters<
-    typeof createSpecification
-  >[1]
+  let body: unknown
+  try {
+    body = await request.json()
+  } catch {
+    return NextResponse.json({ error: 'invalid_json' }, { status: 400 })
+  }
+
+  if (
+    typeof body !== 'object' ||
+    body === null ||
+    typeof (body as { uniqueId?: unknown }).uniqueId !== 'string' ||
+    !(body as { uniqueId: string }).uniqueId.trim() ||
+    typeof (body as { name?: unknown }).name !== 'string' ||
+    !(body as { name: string }).name.trim() ||
+    /^\d+$/.test((body as { uniqueId: string }).uniqueId.trim())
+  ) {
+    return NextResponse.json({ error: 'invalid_request' }, { status: 400 })
+  }

   if (
-    !body?.uniqueId ||
-    typeof body.uniqueId !== 'string' ||
-    !body.uniqueId.trim()
+    await isSlugTaken(db, (body as { uniqueId: string }).uniqueId.trim())
   ) {
-    return NextResponse.json({ error: 'invalid_request' }, { status: 400 })
-  }
-
-  if (await isSlugTaken(db, body.uniqueId)) {
     return NextResponse.json({ error: 'slug_taken' }, { status: 409 })
   }

-  const spec = await createSpecification(db, body)
+  const spec = await createSpecification(
+    db,
+    body as Parameters<typeof createSpecification>[1],
+  )
   return NextResponse.json(spec, { status: 201 })
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/api/specifications/route.ts` around lines 15 - 34, Update the POST
handler to validate and reject malformed/ambiguous payloads before DB calls:
wrap request.json() in a try/catch to return 400 on invalid JSON, add validation
for body.name (e.g., non-empty string) and ensure body.uniqueId is a non-empty
trimmed string and not purely digits (reject /^\d+$/ to avoid numeric-slug
ambiguity), return appropriate 400 responses for validation failures before
calling getRequestSqlServerDataSource/isSlugTaken/createSpecification and only
proceed to isSlugTaken/createSpecification when all checks pass.
lib/dal/requirements-specifications.ts (1)

844-893: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Validate all referenced IDs before the write path.

needsReferenceId is the only foreign key existence-checked here. Invalid requirementAreaId, requirementCategoryId, requirementTypeId, qualityCharacteristicId, riskLevelId, scenarioIds, or normReferenceIds currently fall through to the later inserts, which turns bad client input into SQL failures/500s for both create and update flows.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/dal/requirements-specifications.ts` around lines 844 - 893, The code only
existence-checks needsReferenceId but lets other foreign keys
(requirementAreaId, requirementCategoryId, requirementTypeId,
qualityCharacteristicId, riskLevelId, scenarioIds, normReferenceIds) flow to DB
and cause 500s; add pre-write validation for each referenced id using the same
pattern as needsReferenceId: normalize the id(s) (use
normalizeOptionalForeignKeyId and dedupePositiveIntegerIds already in this
file), then call the appropriate lookup functions (e.g. getRequirementAreaById,
getRequirementCategoryById, getRequirementTypeById,
getQualityCharacteristicById, getRiskLevelById, getScenarioById or a
batch/get-by-spec helper, and getNormReferenceById) to ensure each id exists and
belongs to the relevant specification/tenant, and throw validationError with a
clear message if any lookup returns falsy before returning the prepared object.
lib/requirements/service.ts (1)

1905-1916: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Normalize the DAL deviation buckets before building counts.

countDeviationsBySpecification() returns a Record<string, number> keyed by decision_kind, but this code uses it as if it already had total, pending, approved, and rejected. That makes the summary text and ListDeviationsOutput.counts incorrect whenever the DAL returns raw decision buckets.

Suggested fix
-          const counts = await countDeviationsBySpecification(
-            db,
-            specificationId,
-          )
+          const decisionCounts = await countDeviationsBySpecification(
+            db,
+            specificationId,
+          )
+          const approved =
+            decisionCounts[String(DEVIATION_APPROVED)] ?? 0
+          const rejected =
+            decisionCounts[String(DEVIATION_REJECTED)] ?? 0
+          const total = Object.values(decisionCounts).reduce(
+            (sum, count) => sum + count,
+            0,
+          )
+          const counts = {
+            approved,
+            pending: total - approved - rejected,
+            rejected,
+            total,
+          }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/requirements/service.ts` around lines 1905 - 1916,
countDeviationsBySpecification returns a Record keyed by decision_kind, but the
code treats its result as an object with total/pending/approved/rejected; fix by
normalizing the DAL buckets into a proper counts object before building the
summary and returning ListDeviationsOutput.counts: after calling
countDeviationsBySpecification(db, specificationId) map the returned record into
numeric values for pending, approved, rejected (treat missing keys as 0),
compute total as either the sum of those three or sum of all buckets from the
record, then use that normalized counts object in the summary string and in the
output; update usages around resolveSpecificationIdOrThrow,
listDeviationsForSpecification, countDeviationsBySpecification and the local
counts variable to reference the normalized counts.
🧹 Nitpick comments (2)
scripts/db-sqlserver-admin.mjs (1)

33-36: ⚡ Quick win

Only register actual migration classes.

Right now any exported function is appended to migrations, so a helper export from a migration module would also be treated as a migration. Narrow this to exports that actually look like TypeORM migration classes before passing them on.

Possible tightening
     const module = await import(moduleUrl)
     for (const exported of Object.values(module)) {
-      if (typeof exported === 'function' && !seen.has(exported)) {
+      const isMigrationClass =
+        typeof exported === 'function' &&
+        typeof exported.prototype?.up === 'function' &&
+        typeof exported.prototype?.down === 'function'
+      if (isMigrationClass && !seen.has(exported)) {
         seen.add(exported)
         classes.push(exported)
       }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/db-sqlserver-admin.mjs` around lines 33 - 36, The loop that adds
every exported function into classes (variables exported, seen, classes) should
be tightened to only collect actual TypeORM migration classes; change the
condition so that instead of typeof exported === 'function' you additionally
check that exported.prototype exists and exported.prototype.up and
exported.prototype.down are functions (i.e., the export looks like a Migration
class), and only then add it to seen and classes; this will prevent helper
functions from being treated as migrations.
lib/mcp/server.ts (1)

1386-1407: ⚡ Quick win

Point clients to the exact fields they should echo into these tools.

These descriptions tell clients to use a specification ID or slug, but they never name the source fields from requirements_list_specifications. Please spell out structuredContent.specifications[].id -> specificationId and structuredContent.specifications[].uniqueId -> specificationSlug so clients can chain the tools deterministically.

As per coding guidelines: "State prerequisite tool calls and exact source/destination fields for values clients must echo in tool descriptions."

Also applies to: 1477-1498, 1563-1578

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/mcp/server.ts` around lines 1386 - 1407, Update the tool descriptions in
the inputSchema for the requirements_list_specifications tool to explicitly map
source fields clients must echo: state that
structuredContent.specifications[].id should be passed as specificationId and
structuredContent.specifications[].uniqueId should be passed as
specificationSlug; update the descriptive text on the specificationId and
specificationSlug zod fields to include these source→target mappings so clients
can deterministically chain tool calls (also apply the same explicit mapping
wording to the other occurrences of the same tool descriptions in the file).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/copilot-instructions.md:
- Line 37: Update the sync rule sentence to also require updating
.github/skills/run-spec-audit/references/scrutiny-areas.md whenever you add,
rename, or remove outward-facing lifecycle/specification-item status/MCP
tool/report column/admin-default behavior entries; change the instruction that
references tests/quality/QUALITY.md and tests/quality/functional.test.ts to
explicitly include scrutiny-areas.md and mention the three-file fitness-scenario
contract (QUALITY.md heading, functional.test.ts test case, and
scrutiny-areas.md entry) must be changed together.

In
`@app/`[locale]/specifications/[slug]/requirements-specification-detail-client.tsx:
- Around line 331-355: fetchSpecificationMeta currently swallows non-OK
responses and fetchSpecificationItems returns false but the initial Promise.all
path ignores that, so 500s become treated as "not found"/empty; modify
fetchSpecificationMeta to accept an optional { throwOnError?: boolean } param
(like fetchSpecificationItems) and when res.ok is false either throw new
Error('Failed to refresh specification meta') if throwOnError is true or return
false/undefined so callers know it failed; update the initial loading logic (the
Promise.all that calls fetchSpecificationMeta and fetchSpecificationItems) to
call both with throwOnError: true (or check their boolean return values) and
handle failures by setting a distinct load error/state instead of setting
specificationNotFound or noItems; also update other call sites (the ones around
lines 435-439) to follow the same pattern and not silently treat false as a
successful empty state.
- Around line 321-324: The Set `specificationItemIds` is built from mixed
namespaces (library rows use requirement.id while local rows use
specification_local_requirement.id), causing unrelated catalog requirements to
be excluded; change the construction to only include IDs from library-linked
rows by filtering specificationItems for rows with a `requirement` and mapping
to `requirement.id` (e.g., specificationItemIds = new
Set(specificationItems.filter(r => r.requirement).map(r => r.requirement.id))),
and apply the same filter/map fix to the other occurrence that computes the ID
set used to filter `rightRows`.

In `@app/api/specifications/`[id]/items/[itemId]/route.ts:
- Around line 110-126: The current PATCH does a read with
getSpecificationItemByRef then calls updateSpecificationItemFieldsByItemRef
which repeats the lookup, creating a race where the item can be deleted between
calls and produce a 500 HTML response; remove the initial
getSpecificationItemByRef call and instead call
updateSpecificationItemFieldsByItemRef(db, specificationId, decodedItemRef,
body) directly, then inspect its return value (e.g., affected rows, updated
record, or null) to determine if the item existed—if the update helper indicates
no record was found, return NextResponse.json({ error: 'Item not found in
specification' }, { status: 404 }); otherwise proceed normally. Ensure
updateSpecificationItemFieldsByItemRef consistently returns a falsy value when
no row was updated so this route can reliably map that to a JSON 404.

In `@app/api/specifications/`[id]/items/route.ts:
- Around line 315-320: The catch block currently exposes error.message to
clients; instead, log the actual error server-side (e.g., console.error(error)
or the existing logger if available) and always return a stable JSON message
(e.g., "Failed to unlink requirements") with status 500. Specifically, update
the catch handling that defines const message and calls NextResponse.json so it
does not include error.message, ensure the raw error is logged (use the error
variable) and keep the client-facing response deterministic via
NextResponse.json({ error: 'Failed to unlink requirements' }, { status: 500 }).

In `@devfile.yaml`:
- Around line 161-170: The devfile currently commits a known admin password
(KEYCLOAK_ADMIN_PASSWORD = admin) and exposes Keycloak publicly (endpoints name:
keycloak), creating takeover risk; remove the hardcoded value for
KEYCLOAK_ADMIN_PASSWORD and instead reference an injected secret (e.g., use an
env valueFrom/secretRef like keycloak-admin-secret) and ensure the secret is not
checked into source control, and change the keycloak endpoint exposure from
public to internal (or remove the public exposure) so Keycloak is not publicly
reachable by default while local/dev realms are imported via
KC_IMPORT_REALM_DIR.

In `@docs/database-schema.md`:
- Around line 1155-1161: Update the `unused_1` entry in the
`requirements_specification_items` table documentation to explicitly mark it as
a legacy/deprecated naming exception: state that the column is intentionally
retained under the non-standard name for migration compatibility, is deprecated
and should not be used in new code, and include a short rationale (legacy
placeholder kept for backwards compatibility) alongside the existing “Retired”
text so readers know this violates the normal naming standard intentionally.

In `@docs/requirements-ui-behaviour.md`:
- Around line 298-300: Replace the outdated left-panel label "Krav i
kravunderlag" with the current label "Krav i underlaget" in the sentence
describing library requirement inline detail metadata so the phrase matches
other updated specification-detail docs; update the occurrence that reads "When
a library requirement is opened from the specification list `Krav i
kravunderlag`" to use `Krav i underlaget` (search for that exact phrase to
locate the change).

In `@lib/mcp/server.ts`:
- Around line 1319-1328: The inputSchema.describe for nameSearch overstates
behavior by claiming it filters both Swedish and English names while the handler
(requirements_list_specifications) currently only matches p.name; update the
description text on inputSchema.nameSearch to explicitly state it's a
case-insensitive substring filter applied to the primary name field (p.name)
only, or alternatively implement the intended bilingual matching in the
requirements_list_specifications query (adding p.name_sv to the filter);
reference inputSchema.nameSearch and the requirements_list_specifications
handler / p.name filter when making the change.

In `@lib/slug.ts`:
- Around line 38-39: The JSDoc example in lib/slug.ts showing input
"Säkerhetslyft Q2" → "SAKLYFT-INFOR-Q2" is incorrect; run the actual slug
function (the JSDoc block above the slug generation implementation) with that
input to observe the real output and replace the example output string to match
the function's behavior. Update only the comment example (the input/output pair)
in the JSDoc above the slug function so it reflects the actual returned slug for
"Säkerhetslyft Q2".

In `@scripts/db-sqlserver-admin.mjs`:
- Around line 11-20: listMigrationFilenames currently only accepts ".mjs" which
diverges from the runtime DataSource glob (which uses "*.{js,ts}"); update
listMigrationFilenames to use the same extension matcher as the runtime (e.g.,
accept .js and .ts or reuse the runtime's extension list/constant) by changing
the filter in listMigrationFilenames (and referencing MIGRATIONS_DIR and the
function name) so both admin script and lib/typeorm/sqlserver-config.ts share
the same allowed extensions/pattern.

In `@tests/guide/generate-guide.spec.ts`:
- Around line 1296-1299: The current page.waitForResponse call that sets
deviationResPromise uses only a URL matcher and can match the initial GET;
update the wait to target the POST submit response by adding a predicate that
checks both the URL (/\/api\/specification-item-deviations\//) and that
request.method() === 'POST' (i.e., change the page.waitForResponse usage where
deviationResPromise is defined to only resolve for POST requests), so the
promise only resolves on the submit POST rather than the earlier GET.

In `@tests/integration/specifications-list.md`:
- Around line 48-52: Reword the repeated step sentences that start with "Assert"
in the specifications list so they don't all begin the same way; for example
change one or two of the lines like "Assert the browser is on
`/sv/specifications`" or "Assert the page title contains 'Kravunderlag'" to
"Verify the browser is on `/sv/specifications`" or "Check that the page title
contains 'Kravunderlag'" to satisfy the style rule while keeping the same
assertions and wording otherwise.

---

Outside diff comments:
In `@app/api/specifications/route.ts`:
- Around line 15-34: Update the POST handler to validate and reject
malformed/ambiguous payloads before DB calls: wrap request.json() in a try/catch
to return 400 on invalid JSON, add validation for body.name (e.g., non-empty
string) and ensure body.uniqueId is a non-empty trimmed string and not purely
digits (reject /^\d+$/ to avoid numeric-slug ambiguity), return appropriate 400
responses for validation failures before calling
getRequestSqlServerDataSource/isSlugTaken/createSpecification and only proceed
to isSlugTaken/createSpecification when all checks pass.

In `@lib/dal/requirements-specifications.ts`:
- Around line 844-893: The code only existence-checks needsReferenceId but lets
other foreign keys (requirementAreaId, requirementCategoryId, requirementTypeId,
qualityCharacteristicId, riskLevelId, scenarioIds, normReferenceIds) flow to DB
and cause 500s; add pre-write validation for each referenced id using the same
pattern as needsReferenceId: normalize the id(s) (use
normalizeOptionalForeignKeyId and dedupePositiveIntegerIds already in this
file), then call the appropriate lookup functions (e.g. getRequirementAreaById,
getRequirementCategoryById, getRequirementTypeById,
getQualityCharacteristicById, getRiskLevelById, getScenarioById or a
batch/get-by-spec helper, and getNormReferenceById) to ensure each id exists and
belongs to the relevant specification/tenant, and throw validationError with a
clear message if any lookup returns falsy before returning the prepared object.

In `@lib/requirements/service.ts`:
- Around line 1905-1916: countDeviationsBySpecification returns a Record keyed
by decision_kind, but the code treats its result as an object with
total/pending/approved/rejected; fix by normalizing the DAL buckets into a
proper counts object before building the summary and returning
ListDeviationsOutput.counts: after calling countDeviationsBySpecification(db,
specificationId) map the returned record into numeric values for pending,
approved, rejected (treat missing keys as 0), compute total as either the sum of
those three or sum of all buckets from the record, then use that normalized
counts object in the summary string and in the output; update usages around
resolveSpecificationIdOrThrow, listDeviationsForSpecification,
countDeviationsBySpecification and the local counts variable to reference the
normalized counts.

In `@tests/guide/generate-guide.spec.ts`:
- Around line 1222-1233: The test swallows the waitFor timeout and then silently
skips the deviation workflow when no rows are present; update the block around
page.locator('[data-specification-detail-list-panel="items"]').waitFor(...) and
the subsequent allRows/rowCount check so that the waitFor error is not caught
(or rethrow the error) and add an explicit assertion that rowCount > 0 (throwing
a clear error message referencing the specification panel) instead of simply
skipping when rowCount is 0; reference the page.locator call, the allRows
locator, and the rowCount variable when making these changes.

In `@tests/quality/QUALITY.md`:
- Around line 85-127: Update the outdated line anchors and tests to point at the
current locations of the archiving/publishing logic: locate initiateArchiving()
and transitionStatus() in lib/dal/requirements.ts (they now live earlier than
the anchors in QUALITY.md) and correct the quoted line ranges in the Scenario 2
and Scenario 3 sections; also re-run and update the functional test
selector/test case wording if necessary so the verification commands and test
name match the updated code positions and behavior.

---

Nitpick comments:
In `@lib/mcp/server.ts`:
- Around line 1386-1407: Update the tool descriptions in the inputSchema for the
requirements_list_specifications tool to explicitly map source fields clients
must echo: state that structuredContent.specifications[].id should be passed as
specificationId and structuredContent.specifications[].uniqueId should be passed
as specificationSlug; update the descriptive text on the specificationId and
specificationSlug zod fields to include these source→target mappings so clients
can deterministically chain tool calls (also apply the same explicit mapping
wording to the other occurrences of the same tool descriptions in the file).

In `@scripts/db-sqlserver-admin.mjs`:
- Around line 33-36: The loop that adds every exported function into classes
(variables exported, seen, classes) should be tightened to only collect actual
TypeORM migration classes; change the condition so that instead of typeof
exported === 'function' you additionally check that exported.prototype exists
and exported.prototype.up and exported.prototype.down are functions (i.e., the
export looks like a Migration class), and only then add it to seen and classes;
this will prevent helper functions from being treated as migrations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8876d443-41ed-4b49-a049-049ff7cd9a94

📥 Commits

Reviewing files that changed from the base of the PR and between af74721 and d626a1c.

⛔ Files ignored due to path filters (1)
  • docs/guide/images/029-krav-i-kravunderlag-expanderat.png is excluded by !**/*.png
📒 Files selected for processing (104)
  • .github/copilot-instructions.md
  • .github/instructions/database-schema.instructions.md
  • .github/instructions/detail-pane-layout.instructions.md
  • .github/instructions/quality-spec.instructions.md
  • .github/skills/run-spec-audit/references/integration-contracts.md
  • .github/skills/run-spec-audit/references/scrutiny-areas.md
  • .github/skills/update-guide-spec/SKILL.md
  • README.md
  • app/[locale]/requirements/[id]/_detail/AddToSpecificationDialog.tsx
  • app/[locale]/requirements/[id]/_detail/RequirementActionRail.tsx
  • app/[locale]/requirements/[id]/_detail/RequirementReportMenu.tsx
  • app/[locale]/requirements/[id]/_detail/types.ts
  • app/[locale]/requirements/[id]/_detail/use-add-to-specification-dialog.ts
  • app/[locale]/requirements/[id]/_detail/use-deviation-workflow.ts
  • app/[locale]/requirements/[id]/_detail/use-specification-item-context.ts
  • app/[locale]/requirements/[id]/requirement-detail-client.tsx
  • app/[locale]/specifications/[slug]/page.tsx
  • app/[locale]/specifications/[slug]/reports/print/list/page.tsx
  • app/[locale]/specifications/[slug]/requirements-specification-detail-client.tsx
  • app/[locale]/specifications/[slug]/specification-edit-panel.tsx
  • app/[locale]/specifications/specifications-client.tsx
  • app/api/catalog/specification-item-statuses/[id]/route.ts
  • app/api/catalog/specification-item-statuses/route.ts
  • app/api/specification-item-deviations/[itemId]/route.ts
  • app/api/specifications/[id]/deviations/route.ts
  • app/api/specifications/[id]/items/[itemId]/route.ts
  • app/api/specifications/[id]/items/route.ts
  • app/api/specifications/[id]/local-requirements/[localRequirementId]/route.ts
  • app/api/specifications/[id]/local-requirements/route.ts
  • app/api/specifications/[id]/needs-references/route.ts
  • app/api/specifications/[id]/report-items/route.ts
  • app/api/specifications/[id]/route.ts
  • app/api/specifications/route.ts
  • components/Navigation.tsx
  • components/SpecificationLocalRequirementDetailClient.tsx
  • cspell.jsonc
  • dev/keycloak/realm-kravhantering-dev.json
  • devfile.yaml
  • docs/arkitekturbeskrivning-kravhantering.md
  • docs/auth-developer-workflow.md
  • docs/auth-how-it-works.md
  • docs/database-schema.md
  • docs/developer-mode-overlay.md
  • docs/dogfood-seed.md
  • docs/guide/README.md
  • docs/lifecycle-workflow.md
  • docs/mcp-server-contributor-guide.md
  • docs/mcp-server-user-guide.md
  • docs/openshift-devspaces.md
  • docs/requirements-ui-behaviour.md
  • docs/security-ci.md
  • docs/sql-server-developer-workflow.md
  • lib/dal/deviations.ts
  • lib/dal/requirements-specifications.ts
  • lib/dal/requirements.ts
  • lib/dal/specification-item-statuses.ts
  • lib/mcp/server.ts
  • lib/reports/data/fetch-deviation.ts
  • lib/reports/data/fetch-specification-items.ts
  • lib/reports/templates/deviation-review-template.ts
  • lib/requirements/auth.ts
  • lib/requirements/service.ts
  • lib/slug.ts
  • messages/en.json
  • messages/sv.json
  • scripts/__tests__/db-sqlserver-admin.test.mjs
  • scripts/db-sqlserver-admin.mjs
  • tests/guide/generate-guide.spec.ts
  • tests/integration/developer-mode-overlay.md
  • tests/integration/developer-mode-overlay.spec.ts
  • tests/integration/requirements-specification-detail.md
  • tests/integration/requirements-specification-detail.spec.ts
  • tests/integration/specifications-list.md
  • tests/integration/specifications-list.spec.ts
  • tests/quality/QUALITY.md
  • tests/quality/functional.test.ts
  • tests/support/oidc-mock.ts
  • tests/unit/deviations-dal.test.ts
  • tests/unit/dogfood-seed.test.ts
  • tests/unit/mcp-http.test.ts
  • tests/unit/reference-data-developer-mode.test.tsx
  • tests/unit/report-error-details.test.ts
  • tests/unit/requirement-detail-client.test.tsx
  • tests/unit/requirement-detail-hooks.test.tsx
  • tests/unit/requirement-report-menu.test.tsx
  • tests/unit/requirements-dal.test.ts
  • tests/unit/requirements-service.test.ts
  • tests/unit/requirements-specification-detail-client.test.tsx
  • tests/unit/requirements-specification-item-route.test.ts
  • tests/unit/requirements-specification-items-route.test.ts
  • tests/unit/requirements-specifications-dal.test.ts
  • tests/unit/requirements-table.test.tsx
  • tests/unit/specification-edit-panel.test.tsx
  • tests/unit/specification-item-statuses-client.test.tsx
  • tests/unit/specification-item-statuses-dal.test.ts
  • tests/unit/specification-local-requirement-detail-client.test.tsx
  • tests/unit/specification-local-requirement-route.test.ts
  • tests/unit/specification-report-pages.test.tsx
  • tests/unit/specifications-client.test.tsx
  • tests/unit/specifications-page.test.tsx
  • tests/unit/taxonomy-routes.test.ts
  • typeorm/seed-dogfood-build.mjs
  • typeorm/seed-dogfood.mjs
  • typeorm/seed.mjs
✅ Files skipped from review due to trivial changes (19)
  • .github/instructions/quality-spec.instructions.md
  • docs/auth-how-it-works.md
  • docs/sql-server-developer-workflow.md
  • .github/instructions/detail-pane-layout.instructions.md
  • .github/instructions/database-schema.instructions.md
  • docs/security-ci.md
  • README.md
  • tests/unit/report-error-details.test.ts
  • docs/openshift-devspaces.md
  • docs/mcp-server-user-guide.md
  • docs/auth-developer-workflow.md
  • app/api/specifications/[id]/route.ts
  • docs/developer-mode-overlay.md
  • lib/reports/templates/deviation-review-template.ts
  • tests/integration/requirements-specification-detail.spec.ts
  • .github/skills/update-guide-spec/SKILL.md
  • tests/integration/developer-mode-overlay.md
  • docs/guide/README.md
  • tests/unit/dogfood-seed.test.ts
🚧 Files skipped from review as they are similar to previous changes (22)
  • app/api/specifications/[id]/needs-references/route.ts
  • tests/unit/mcp-http.test.ts
  • app/api/catalog/specification-item-statuses/[id]/route.ts
  • docs/mcp-server-contributor-guide.md
  • app/[locale]/requirements/[id]/_detail/types.ts
  • tests/integration/developer-mode-overlay.spec.ts
  • lib/dal/specification-item-statuses.ts
  • app/api/specifications/[id]/deviations/route.ts
  • app/[locale]/requirements/[id]/_detail/use-deviation-workflow.ts
  • app/[locale]/requirements/[id]/_detail/AddToSpecificationDialog.tsx
  • app/api/specifications/[id]/local-requirements/[localRequirementId]/route.ts
  • app/[locale]/requirements/[id]/_detail/RequirementReportMenu.tsx
  • tests/integration/specifications-list.spec.ts
  • cspell.jsonc
  • app/[locale]/requirements/[id]/_detail/use-add-to-specification-dialog.ts
  • app/[locale]/requirements/[id]/_detail/use-specification-item-context.ts
  • docs/lifecycle-workflow.md
  • components/SpecificationLocalRequirementDetailClient.tsx
  • docs/arkitekturbeskrivning-kravhantering.md
  • .github/skills/run-spec-audit/references/scrutiny-areas.md
  • tests/quality/functional.test.ts
  • lib/dal/deviations.ts

Comment thread .github/copilot-instructions.md Outdated
Comment thread app/api/specifications/[id]/items/[itemId]/route.ts Outdated
Comment thread app/api/specifications/[id]/items/route.ts Outdated
Comment thread lib/mcp/server.ts
Comment thread lib/slug.ts Outdated
Comment thread scripts/db-sqlserver-admin.mjs
Comment thread tests/guide/generate-guide.spec.ts
Comment thread tests/integration/specifications-list.md
@johlju

johlju commented May 3, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@johlju

johlju commented May 3, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 3, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
tests/quality/QUALITY.md (1)

58-385: ⚠️ Potential issue | 🔴 Critical

Split Scenario 12 into three matching test names across all three files.

Scenario 12 in QUALITY.md and scrutiny-areas.md has been split into three separate tests in functional.test.ts (12a, 12b, 12c), but QUALITY.md still contains a single unified Scenario 12 heading. The three-file fitness scenario sibling contract requires the test name in functional.test.ts to match verbatim the heading in QUALITY.md and the entry in scrutiny-areas.md.

Either split Scenario 12 in QUALITY.md into three separate scenario sections (Scenario 12a, 12b, 12c) with matching updates to scrutiny-areas.md, or consolidate the three test cases in functional.test.ts back into a single it('Scenario 12: ...') test. Keep all three components in sync.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/quality/QUALITY.md` around lines 58 - 385, The markdown heading
"Scenario 12" in QUALITY.md no longer matches the three test names added in
functional.test.ts ("Scenario 12a", "Scenario 12b", "Scenario 12c") (and the
sibling entry in scrutiny-areas.md), causing the three-file contract to break;
either split the single "Scenario 12" heading/content in QUALITY.md into three
verbatim headings "Scenario 12a", "Scenario 12b", "Scenario 12c" and make the
identical changes in scrutiny-areas.md, or revert the three tests in
functional.test.ts back into one single test named exactly "Scenario 12:
concurrent archiving attempts are atomic and strictly targeted"; ensure the
scenario headings in QUALITY.md/scrutiny-areas.md and test names in
functional.test.ts match verbatim.
lib/mcp/server.ts (2)

1386-1407: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Make these tool descriptions name the exact fields clients must echo.

The renamed tool contracts still stop at “use specificationId/specificationSlug” or “pass requirementIds”. Please spell out the copy path in the description, e.g. requirements_list_specifications.specifications[].id -> specificationId, requirements_list_specifications.specifications[].uniqueId -> specificationSlug, and the relevant [].id -> requirementIds source for add/remove. That keeps the MCP surface self-describing for clients. As per coding guidelines: "State prerequisite tool calls and exact source/destination fields for values clients must echo in tool descriptions" and "Do not rely on user docs alone to teach MCP clients how to call a tool; teach via tool contract definition."

📝 Proposed description updates
-        'List requirements (krav) linked to a specific requirements specification, with optional description search. Identify the specification with specificationId (numeric) or specificationSlug (e.g. "SAKLYFT-INFOR-Q2") from requirements_list_specifications.',
+        'List requirements (krav) linked to a specific requirements specification, with optional description search. First call requirements_list_specifications, then copy specifications[].id to specificationId or specifications[].uniqueId to specificationSlug.',

-        'Link one or more requirements to a requirements specification. Requirements must have a published version; those without are skipped and returned in skippedIds. Optionally attach a needs reference text to all added items. Identify the specification with specificationId (numeric) or specificationSlug (e.g. "SAKLYFT-INFOR-Q2").',
+        'Link one or more requirements to a requirements specification. First call requirements_list_specifications and copy specifications[].id to specificationId or specifications[].uniqueId to specificationSlug. Populate requirementIds from requirements_query_catalog.items[].id or requirements_get_requirement.requirement.id. Requirements must have a published version; those without are skipped and returned in skippedIds. Optionally attach a needs reference text to all added items.',

-        'Unlink one or more requirements from a requirements specification. The requirements themselves are not deleted. Identify the specification with specificationId (numeric) or specificationSlug (e.g. "SAKLYFT-INFOR-Q2").',
+        'Unlink one or more requirements from a requirements specification. First call requirements_list_specifications and copy specifications[].id to specificationId or specifications[].uniqueId to specificationSlug. Populate requirementIds from requirements_get_specification_items.items[].id. The requirements themselves are not deleted.',

Also applies to: 1477-1504, 1563-1584

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/mcp/server.ts` around lines 1386 - 1407, Update the tool description
strings so they explicitly tell clients which exact fields to copy from prior
tool outputs into these inputs: e.g. for the requirements_list_specifications
tool, state that clients must echo
requirements_list_specifications.specifications[].id -> specificationId and
requirements_list_specifications.specifications[].uniqueId -> specificationSlug;
for add/remove requirement tools, state that
requirements_list_specifications.specifications[].requirements[].id ->
requirementIds (or the exact array path used). Edit the human-readable
description in the tool contract where inputSchema and fields specificationId,
specificationSlug, and requirementIds are declared so the copy paths are
verbatim in the text (refer to inputSchema, specificationId, specificationSlug,
and requirementIds and update the top-level tool description strings and any
similar descriptions elsewhere mentioned).

1310-1631: ⚠️ Potential issue | 🟠 Major

Add a Fitness Scenario for the new specification MCP tools' behavior and contracts.

These four tools (requirements_list_specifications, requirements_get_specification_items, requirements_add_to_specification, requirements_remove_from_specification) are new outward-facing MCP operations. Per the coding guidelines, new MCP tool additions require a Fitness Scenario in tests/quality/QUALITY.md with a matching test in tests/quality/functional.test.ts and scrutiny entry in .github/skills/run-spec-audit/references/scrutiny-areas.md.

Scenario 10 (MCP tool inventory) only verifies that the tool count matches documentation; it does not test the tools' actual behavior, schema validation, field contracts, or error handling. The specification tools need a dedicated behavior scenario covering their input/output schemas, identifier validation (e.g., exactly-one-of-two logic for specificationId/specificationSlug), and correct data flow through service layer to database DAL.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/mcp/server.ts` around lines 1310 - 1631, Add a Fitness Scenario and tests
for the four new MCP tools to validate their behavior and contracts: create a
scenario entry in tests/quality/QUALITY.md that describes expected input/output
schemas and behaviors for requirements_list_specifications,
requirements_get_specification_items, requirements_add_to_specification, and
requirements_remove_from_specification; add corresponding tests in
tests/quality/functional.test.ts that exercise schema validation (including the
exactly-one-of-two superRefine rule for specificationId vs specificationSlug),
responseFormat/locale handling, happy-path data flow through service methods
listSpecifications, getSpecificationItems, addToSpecification,
removeFromSpecification, and error cases (validation failures and service
errors); and add a scrutiny note in
.github/skills/run-spec-audit/references/scrutiny-areas.md referencing the new
scenario and listing the specific contract checks (schemas, identifier
validation, skippedIds behavior for addToSpecification, and
removedCount/addedCount semantics).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/api/specifications/`[id]/items/[itemId]/route.ts:
- Line 110: Guard the decodeURIComponent call for itemId to avoid uncaught
URIError: wrap the call to decodeURIComponent(itemId) inside a try/catch in the
route handler (where decodedItemRef is assigned), and on failure return a 400
JSON response (e.g., { error: "Invalid itemId" }) instead of throwing; ensure
the catch only handles URIError/decoding failures and preserves normal flow for
valid itemId values.

In `@tests/quality/QUALITY.md`:
- Around line 189-204: Update the documentation in tests/quality/QUALITY.md to
use the correct deviated status id: replace the hardcoded
"specificationItemStatusId = 5" with the implemented value
(DEVIATED_SPECIFICATION_ITEM_STATUS_ID, which is 2) or explicitly state
"specificationItemStatusId = 2"; ensure the scenario text that references the
guards in updateSpecificationItemFields() and
updateSpecificationLocalRequirementFields() reflects the actual constant used so
the narrative matches the implementation.

---

Outside diff comments:
In `@lib/mcp/server.ts`:
- Around line 1386-1407: Update the tool description strings so they explicitly
tell clients which exact fields to copy from prior tool outputs into these
inputs: e.g. for the requirements_list_specifications tool, state that clients
must echo requirements_list_specifications.specifications[].id ->
specificationId and requirements_list_specifications.specifications[].uniqueId
-> specificationSlug; for add/remove requirement tools, state that
requirements_list_specifications.specifications[].requirements[].id ->
requirementIds (or the exact array path used). Edit the human-readable
description in the tool contract where inputSchema and fields specificationId,
specificationSlug, and requirementIds are declared so the copy paths are
verbatim in the text (refer to inputSchema, specificationId, specificationSlug,
and requirementIds and update the top-level tool description strings and any
similar descriptions elsewhere mentioned).
- Around line 1310-1631: Add a Fitness Scenario and tests for the four new MCP
tools to validate their behavior and contracts: create a scenario entry in
tests/quality/QUALITY.md that describes expected input/output schemas and
behaviors for requirements_list_specifications,
requirements_get_specification_items, requirements_add_to_specification, and
requirements_remove_from_specification; add corresponding tests in
tests/quality/functional.test.ts that exercise schema validation (including the
exactly-one-of-two superRefine rule for specificationId vs specificationSlug),
responseFormat/locale handling, happy-path data flow through service methods
listSpecifications, getSpecificationItems, addToSpecification,
removeFromSpecification, and error cases (validation failures and service
errors); and add a scrutiny note in
.github/skills/run-spec-audit/references/scrutiny-areas.md referencing the new
scenario and listing the specific contract checks (schemas, identifier
validation, skippedIds behavior for addToSpecification, and
removedCount/addedCount semantics).

In `@tests/quality/QUALITY.md`:
- Around line 58-385: The markdown heading "Scenario 12" in QUALITY.md no longer
matches the three test names added in functional.test.ts ("Scenario 12a",
"Scenario 12b", "Scenario 12c") (and the sibling entry in scrutiny-areas.md),
causing the three-file contract to break; either split the single "Scenario 12"
heading/content in QUALITY.md into three verbatim headings "Scenario 12a",
"Scenario 12b", "Scenario 12c" and make the identical changes in
scrutiny-areas.md, or revert the three tests in functional.test.ts back into one
single test named exactly "Scenario 12: concurrent archiving attempts are atomic
and strictly targeted"; ensure the scenario headings in
QUALITY.md/scrutiny-areas.md and test names in functional.test.ts match
verbatim.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fda04c25-ae26-431f-b54a-c58384bece4c

📥 Commits

Reviewing files that changed from the base of the PR and between d626a1c and 2282ab9.

📒 Files selected for processing (9)
  • .github/copilot-instructions.md
  • app/api/specifications/[id]/items/[itemId]/route.ts
  • app/api/specifications/[id]/items/route.ts
  • docs/requirements-ui-behaviour.md
  • lib/mcp/server.ts
  • lib/slug.ts
  • tests/guide/generate-guide.spec.ts
  • tests/quality/QUALITY.md
  • tests/unit/requirements-specification-items-route.test.ts
✅ Files skipped from review due to trivial changes (1)
  • tests/guide/generate-guide.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/api/specifications/[id]/items/route.ts

Comment thread app/api/specifications/[id]/items/[itemId]/route.ts Outdated
Comment thread tests/quality/QUALITY.md
@johlju
johlju merged commit e2614b0 into viscalyx:main May 3, 2026
9 checks passed
@johlju
johlju deleted the f/rename-to-spec branch May 3, 2026 17:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant