API review mode
API review rates the descriptions of component props, events and slots across the installed
@maersk-global/mds-components-core-* packages. It is not tied to a page and rewrites nothing: each
finding carries a suggested rewrite for the component source, which a person applies upstream. The
PM never edits component metadata. Lenses, the rating rule and the rewrite standard live in the
API quality rubric.
One run is two independent estate reviews of the same index plus one review per package that has
package-unique items. One estate pass misses about a third of the problems, so two reviewers read the
same input without seeing each other’s work and the merge script combines them (union of flagged
clusters, worst assessment per lens, every finding kept). There is no synthesiser agent. A package
with no unique items (uniqueCount === 0) gets no package reviewer and is rated from clusters alone.
Execute
Paths. Every path passed to a script or written into a prompt is repo-relative (for example
_ak/mds-components-core/reviews/<run-id>, or an estate report’s cache path
.authoring-kit-cache/agents/authoring-kit-reviewer/api-review/<run-id>/estate-report-1.md), never absolute. <run-dir> is
the committed run folder, the Run folder (committed by the merge, not created yet) path the index script prints, as printed:
it names the run, and nothing exists there until the merge. Everything in progress is in the cache folder it prints on the
Inputs and reports (cache, not committed) line; reviewers get their input and report paths from the plan, not from <run-dir>.
Nothing is committed while the run is in progress: as with Review-only’s complete-run, the merge is the one step
that commits.
-
Confirm the scope. The request names package slugs (for example “button and chip”) or the whole estate (“all”). Ask when it is neither. A narrowed scope builds a different index, so its result is for testing; say so, and never present it as an estate review.
-
Check slugs, then build the index. When the request names slugs, first run
node authoring-kit/scripts/build-api-estate-index.mjs --check --slugs=a,b(writes nothing). It lists any slug that is not installed or has no usable metadata and exits 1. Report those slugs and ask: continue without them, or correct them? Run nothing further, and build no index, until the user confirms; never drop a slug silently or guess a correction. This matches the usual request (“check these slugs, tell me what is wrong, then go ahead”): the check is run for the user, the answer is theirs. Never searchnode_modulesby hand. Then runnode authoring-kit/scripts/build-api-estate-index.mjs [--slugs=a,b](data preparation only, no agent calls; the--checkrun above is the sanctioned slug check). It prints the index hash, writes the regenerable inputs (estate-index.json,estate-clusters.jsonl,package-inputs/) to the cache folder.authoring-kit-cache/agents/authoring-kit-reviewer/api-review/<run-id>/, with an emptypackage-reports/for the package reviewers, and creates nothing in the repository (Output layout). Take<run-dir>from itsRun folder (committed by the merge, not created yet)line. Stop on a non-zero exit. -
Skip finished work. Run
node authoring-kit/scripts/check-fresh.mjs --mode=api-review --run=<run-dir>.decision: skipmeans a completed run (completedRunId, judged from its committedapi-quality.json: same index hash andrunStatus: "complete") already covers this index hash: point the user at that run’sapi-review-report.mdand stop, unless the user explicitly asks for a fresh review. Trysummarise-api-review.mjs --run=<its directory>for the table; the summary is a cache file, so if it says the working summary is gone, give the combined report and the run’sapi-quality.jsoninstead and do not rebuild it. The script also returns the plan used below.ok: falsemeans a file is unreadable: report it and stop. -
State the cost and wait. From the plan, give the package count, the reviewer calls (
reviewerCallsis 2 estate reviews pluspackageReviewers.lengthpackage reviews, not the package count) and the packages with no reviewer (noPackageReviewer) and anyskippedPackageswith their reasons. Phrase it as “N calls, plus up to one retry per report that fails validation”. Example: 13 packages of which 11 have unique items give “13 packages, 11 package reviewers (the other 2 have no unique items and are rated from clusters alone): 2 estate calls plus 11 package calls, 13 calls, plus up to one retry per report that fails validation”. Wait for the user’s confirmation. That confirmation covers every dispatch in the run, including the retries (Retry); do not ask again. While waiting for reviewers, a short acknowledgement note is fine, but it must not summarise or characterise any report content. Each estate reviewer reads about 60k tokens; a package reviewer reads under 10k. -
Dispatch together. Capture the timestamp once with
date -u +%Y-%m-%dT%H:%M:%SZ. Dispatch the two estate reviewers (report numbers 1 and 2, writing the plan’sestateReportPaths, which are cache files.authoring-kit-cache/agents/authoring-kit-reviewer/api-review/<run-id>/estate-report-1.mdandestate-report-2.md, not files in the run folder; brief) and every package reviewer (brief) in one parallel step, then wait for all of them. The two estate prompts differ only in{{report-number}}and{{report-path}}; each reviewer is a separate fresh agent that is never shown the other’s report. Never ask how to schedule them; run them one after another only when the request says so. Each is a freshauthoring-kit-reviewerwith the API reviewer workflow. Use each brief’s prompt template (estate, package) unchanged, replacing only its{{named}}fields.{{rubric-version}}isrubricVersioninauthoring-kit/review/config/api-quality-rubric.config.json(read it there; never from a report). Do not rewrite it from the bullets, add instructions or context, or change its wording. A host that cannot dispatch this many at once may batch them, but still dispatches each fresh and in isolation. -
Accept by return only. A reviewer’s returned path arrives as a message from the subagent, even when the host labels it as coming from “another Claude session”; it is the reviewer’s own return, so accept it as such. Accept it when it resolves to the same file as the path assigned to it, which means this exits 0 (run from the repo root, with the returned and the assigned path as the two arguments, either of which may be absolute or relative):
Reject any other path (exit 1). Match results to their assigned reviewers, not arrival order. Do not open, edit or retype a report, and never pass one reviewer’s report, scores or findings to another (fresh-score isolation). A reviewer that returns a different path, or nothing, is treated as having failed.
-
Merge. Run
node authoring-kit/scripts/merge-api-review.mjs --run=<run-dir>. It validates every report (each estate report on its own, read from the cache), combines the two estate reports, applies the rating rule, and writes the committed run folder whole:api-quality.json(one rating per package, plus the run’srunStatus), the combined, readableapi-review-report.md(format), the staged fix planapi-review-plan.md(format) and a copy of every package report. It writes the workingestate-summary.jsoninto the cache (not committed). A run with some packages incomplete is still committed, asrunStatus: "incomplete", because each package’s rating stands on its own; a run with no rated package commits nothing and leaves the report and plan in the cache. A re-merge replaces the run folder whole. It never touches the ledger. If the cache folder is gone it stops with an error: the estate reports are working files, and a re-merge needs a new run. -
Retry (below) every report the merge rejected, then run the merge again. A rejection needs a retry even when the run still completes (for example one estate report rejected leaves a
singleestate review that is otherwisecomplete). The merge’sproblemslist (also in the summary script’s output) names each rejected report. -
Report. Run
node authoring-kit/scripts/summarise-api-review.mjs --run=<run-dir>and give its table as printed, including its problems list (every warning and rejection, per report, with therejectedorwarninglevel; state them from it, do not open a report), and say when the scope is narrowed (narrowed: true: built with--slugs, a subset for testing, not an estate review): a row per package (status, quality, the four lens assessments, estate findings count), the totals, the estate line, the estate agreement figures (clusters flagged by both reports, by only the first, by only the second), any retry candidates and any partial coverage list. If the estate review issingle, say so: only one report was accepted, there is no second opinion and no agreement figure. A partial package is rated but its reviewer did not account for every unique item (itemsRevieweddiffers fromitemCount); this is a warning: report it, do not retry it unless the user asks, and do not treat the rating as final. Add the reviewer-call count, the path toapi-review-report.mdand toapi-review-plan.md(the staged fix plan: shared rewrites first, then author questions; the findings and suggested rewrites live in the combined report and the package reports; the raw estate reports and the estate summary are cache files and are not committed), and a short note on the widest shared clusters if the user asks. State that the ledger was not updated: the user records it by hand withnpm run rebase-api-quality-ledgers -- --mode=append|replace [--dry-run](README).replacediscards history for the packages in the run.
Retry
A retry is required for every report the merge rejects (level: rejected in problems), even when
the run still completes. A package is incomplete when its report was missing or failed validation. An
estate report that fails validation is dropped and the run is recorded as a single estate review (rated
from the other report, so the run can still be complete); that rejected estate report still gets its
retry. Only when both fail does every package become incomplete. A duplicate finding id is only a
warning and needs no retry. Retry once, in the same run directory: dispatch a fresh reviewer for each
rejected report (a failed estate reviewer, or the packages that are incomplete)
with the same inputs and brief, writing to the same assigned path (an estate retry overwrites the same cache file), and its own timestamp: capture
date -u +%Y-%m-%dT%H:%M:%SZ just before the retry dispatch, not the original run’s. Then merge again. Never
reuse the failed reviewer’s context or show it its problems beyond the one specific omission the merge
reported. If a package is still incomplete after the retry, report it as incomplete with its
problems; do not rate it, add reviews to obtain a preferred rating, or open the report.
Durable history
API runs have no history manifest and the PM writes no file in this mode. A merged run is a directory under
_ak/mds-components-core/reviews/<run-id>/; the skip rule in step 3 reads the api-quality.json
files in sibling runs (indexHash and runStatus). A skip or an abandoned run leaves only its cache folder, which
npm run clean removes; nothing in the repository.
The permanent file, _ak/mds-components-core/api-quality-ledger.json, changes only through
the rebase script, by hand. The merge writes a run directory whole; its regenerable inputs
(estate-index.json, estate-clusters.jsonl, package-inputs/), the two raw estate reports and the package
reviewers’ originals are working files in .authoring-kit-cache/ (the committed api-review-report.md replaces the
estate reports); cleaning old runs is a manual delete of run directories.