@mmerterden/multi-agent-pipeline 20.2.1 → 20.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +912 -1
- package/README.md +104 -81
- package/README.tr.md +103 -62
- package/docs/FIGMA_PIPELINE.md +35 -35
- package/docs/adr/0006-skills-core-external-split.md +1 -1
- package/docs/adr/0007-multi-tool-adapter-framework.md +6 -0
- package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +7 -0
- package/docs/architecture.md +50 -14
- package/docs/best-practices.md +1 -1
- package/docs/ecosystem.md +56 -32
- package/docs/facts.json +10 -10
- package/docs/features.md +97 -5
- package/docs/recovery-guide.md +7 -14
- package/docs/server-readiness.md +31 -24
- package/index.js +1 -1
- package/install/_common.mjs +3 -5
- package/install/_platform-filter.mjs +23 -1
- package/install/_unattended-profile.mjs +321 -75
- package/install/claude.mjs +51 -10
- package/install/codex.mjs +2 -0
- package/install/copilot.mjs +2 -0
- package/install/index.mjs +30 -17
- package/install/templates/claude-hooks.json +16 -5
- package/install/templates/copilot-instructions.md +1 -1
- package/install/templates/multi-agent-autopilot-awake.plist.template +48 -0
- package/install/templates/multi-agent-autopilot.plist.template +12 -5
- package/install/unattended-profile-legacy.json +80 -0
- package/manifest.json +616 -483
- package/package.json +8 -3
- package/pipeline/agents/code-reviewer.md +10 -0
- package/pipeline/agents/plan-critic.md +98 -0
- package/pipeline/agents/security-auditor.md +10 -0
- package/pipeline/agents/task-clarifier.md +10 -0
- package/pipeline/commands/multi-agent/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/analysis/SKILL.md +6 -2
- package/pipeline/commands/multi-agent/analysis-jira/SKILL.md +12 -1
- package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/autopilot/SKILL.md +6 -2
- package/pipeline/commands/multi-agent/autopilot-off/SKILL.md +36 -6
- package/pipeline/commands/multi-agent/autopilot-on/SKILL.md +77 -12
- package/pipeline/commands/multi-agent/autopilot-status/SKILL.md +29 -8
- package/pipeline/commands/multi-agent/build-optimize/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/channels/SKILL.md +9 -9
- package/pipeline/commands/multi-agent/complaint-analysis/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/create-jira/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/design-check/SKILL.md +16 -11
- package/pipeline/commands/multi-agent/diff-explain/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/doctor/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/feedback/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/forget/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/graph/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/help/SKILL.md +37 -39
- package/pipeline/commands/multi-agent/ios-coding-standard/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/issue/SKILL.md +7 -1
- package/pipeline/commands/multi-agent/jira/SKILL.md +7 -1
- package/pipeline/commands/multi-agent/kill/SKILL.md +9 -3
- package/pipeline/commands/multi-agent/language/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/log/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/manual-test/SKILL.md +5 -0
- package/pipeline/commands/multi-agent/model/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/prune-logs/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/prune-prompts/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/purge/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/refactor/SKILL.md +5 -0
- package/pipeline/commands/multi-agent/research/SKILL.md +49 -0
- package/pipeline/commands/multi-agent/resume/SKILL.md +29 -6
- package/pipeline/commands/multi-agent/review/SKILL.md +28 -9
- package/pipeline/commands/multi-agent/review-analysis/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/review-issue/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/review-jira/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/route-off/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/route-on/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/route-status/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/routines/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/save/SKILL.md +6 -2
- package/pipeline/commands/multi-agent/scaffold/SKILL.md +47 -0
- package/pipeline/commands/multi-agent/scan/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/search/SKILL.md +12 -8
- package/pipeline/commands/multi-agent/security-review/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/serve/SKILL.md +62 -0
- package/pipeline/commands/multi-agent/setup/SKILL.md +27 -36
- package/pipeline/commands/multi-agent/stack/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/status/SKILL.md +10 -9
- package/pipeline/commands/multi-agent/steer/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/store-ready/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/sync/SKILL.md +13 -13
- package/pipeline/commands/multi-agent/test/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/test-accessibility/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/test-dark-mode/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/test-dynamic-type/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/test-screenshots/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/testflight-validation/SKILL.md +4 -0
- package/pipeline/commands/multi-agent/uninstall/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/update/SKILL.md +4 -0
- package/pipeline/contract/CHANGELOG.md +74 -0
- package/pipeline/contract/README.md +126 -0
- package/pipeline/contract/build.mjs +427 -0
- package/pipeline/contract/fixtures/answer-result.json +11 -0
- package/pipeline/contract/fixtures/error-invalid-request.json +8 -0
- package/pipeline/contract/fixtures/error-unauthorized.json +5 -0
- package/pipeline/contract/fixtures/error-unsigned.json +5 -0
- package/pipeline/contract/fixtures/issues-empty.json +18 -0
- package/pipeline/contract/fixtures/launch-plan.json +31 -0
- package/pipeline/contract/fixtures/runs-awaiting-question.json +70 -0
- package/pipeline/contract/fixtures/runs-empty.json +6 -0
- package/pipeline/contract/fixtures/runs-failed.json +84 -0
- package/pipeline/contract/fixtures/runs-old-schema.json +70 -0
- package/pipeline/contract/fixtures/runs-pr-opened-redacted.json +101 -0
- package/pipeline/contract/fixtures/runs-pr-opened.json +106 -0
- package/pipeline/contract/fixtures/runs-running.json +84 -0
- package/pipeline/contract/fixtures/worktrees-empty.json +4 -0
- package/pipeline/contract/frozen/toolbox.json +107 -0
- package/pipeline/contract/manifest.json +263 -0
- package/pipeline/contract/types/index.d.ts +343 -0
- package/pipeline/lib/_jira-auth.sh +6 -2
- package/pipeline/lib/account-resolver.sh +1 -1
- package/pipeline/lib/autopilot-state.sh +19 -0
- package/pipeline/lib/context-link-extractor.sh +12 -5
- package/pipeline/lib/credential-inventory.sh +12 -5
- package/pipeline/lib/credential-store.sh +116 -185
- package/pipeline/lib/fetch-confluence.sh +44 -3
- package/pipeline/lib/fetch-document.sh +3 -4
- package/pipeline/lib/fetch-fortify.sh +1 -1
- package/pipeline/lib/figma-mcp-refresh.sh +2 -2
- package/pipeline/lib/figma-token.sh +5 -1
- package/pipeline/lib/issue-fetcher.sh +233 -16
- package/pipeline/lib/json-file-lock.mjs +172 -0
- package/pipeline/lib/model-dispatch.sh +21 -12
- package/pipeline/lib/model-rung.sh +6 -1
- package/pipeline/lib/multi-repo-pipeline.sh +1 -1
- package/pipeline/lib/outbound-gate.mjs +46 -16
- package/pipeline/lib/parse-complaints.sh +14 -7
- package/pipeline/lib/plan-todos.sh +3 -3
- package/pipeline/lib/post-pr-review.sh +9 -9
- package/pipeline/lib/pr-request-location.mjs +85 -0
- package/pipeline/lib/regular-file.mjs +153 -0
- package/pipeline/lib/repo-hygiene.sh +17 -0
- package/pipeline/lib/route-state.sh +5 -1
- package/pipeline/lib/run-paths.sh +3 -2
- package/pipeline/lib/stack-detect.sh +19 -1
- package/pipeline/lib/unattended-profile-check.mjs +178 -0
- package/pipeline/lib/unattended-settings-location.mjs +28 -0
- package/pipeline/lib/unattended.mjs +76 -0
- package/pipeline/lib/unattended.sh +32 -0
- package/pipeline/lib/untrusted.mjs +76 -0
- package/pipeline/lib/user-facing.mjs +82 -0
- package/pipeline/lib/user-facing.sh +58 -0
- package/pipeline/multi-agent-refs/_dev-context.md +1 -1
- package/pipeline/multi-agent-refs/analysis/evidence.md +4 -0
- package/pipeline/multi-agent-refs/analysis/locked.md +2 -2
- package/pipeline/multi-agent-refs/analysis/render.md +4 -3
- package/pipeline/multi-agent-refs/analysis/resolve.md +3 -1
- package/pipeline/multi-agent-refs/analysis/synthesis.md +4 -5
- package/pipeline/multi-agent-refs/analysis-template.md +10 -17
- package/pipeline/multi-agent-refs/channels/jira.md +1 -1
- package/pipeline/multi-agent-refs/component-dispatch.md +3 -3
- package/pipeline/multi-agent-refs/conventions-defaults.md +32 -32
- package/pipeline/multi-agent-refs/cross-cli-contract.md +10 -17
- package/pipeline/multi-agent-refs/features/autopilot-circuit-breaker.md +37 -9
- package/pipeline/multi-agent-refs/features/autopilot-operations.md +277 -0
- package/pipeline/multi-agent-refs/features/constitution.md +196 -0
- package/pipeline/multi-agent-refs/features/doctor.md +6 -3
- package/pipeline/multi-agent-refs/features/external-context-injection.md +6 -1
- package/pipeline/multi-agent-refs/features/jira-context.md +1 -1
- package/pipeline/multi-agent-refs/features/maturity-followup.md +43 -23
- package/pipeline/multi-agent-refs/features/model-fallback.md +9 -0
- package/pipeline/multi-agent-refs/features/phone-api.md +306 -0
- package/pipeline/multi-agent-refs/features/plan-critic.md +159 -0
- package/pipeline/multi-agent-refs/features/research.md +150 -0
- package/pipeline/multi-agent-refs/features/review-decision.md +185 -0
- package/pipeline/multi-agent-refs/features/scaffold.md +160 -0
- package/pipeline/multi-agent-refs/features/security-audit.md +6 -2
- package/pipeline/multi-agent-refs/features/skill-conformance.md +4 -1
- package/pipeline/multi-agent-refs/features/stack-adapters.md +116 -0
- package/pipeline/multi-agent-refs/features/unattended-gates.md +316 -0
- package/pipeline/multi-agent-refs/features/unattended-security.md +731 -0
- package/pipeline/multi-agent-refs/features/url-enrichment.md +2 -2
- package/pipeline/multi-agent-refs/features/usage-reporting.md +127 -35
- package/pipeline/multi-agent-refs/features/verify-by-test.md +1 -1
- package/pipeline/multi-agent-refs/features/visual-evidence.md +7 -7
- package/pipeline/multi-agent-refs/keychain.md +6 -11
- package/pipeline/multi-agent-refs/payload-contracts.md +2 -2
- package/pipeline/multi-agent-refs/phases/log-format.md +2 -3
- package/pipeline/multi-agent-refs/phases/modes.md +10 -12
- package/pipeline/multi-agent-refs/phases/operations.md +11 -5
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +73 -81
- package/pipeline/multi-agent-refs/phases/phase-1-plan.md +22 -22
- package/pipeline/multi-agent-refs/phases/phase-2-dev.md +42 -66
- package/pipeline/multi-agent-refs/phases/phase-3-review.md +45 -79
- package/pipeline/multi-agent-refs/phases/phase-4-commit.md +28 -38
- package/pipeline/multi-agent-refs/phases/phase-5-report.md +27 -25
- package/pipeline/multi-agent-refs/phases.md +1 -1
- package/pipeline/multi-agent-refs/picker-contract.md +1 -1
- package/pipeline/multi-agent-refs/progress-contract.md +13 -16
- package/pipeline/multi-agent-refs/readiness-review.md +1 -1
- package/pipeline/multi-agent-refs/research/engine.md +91 -0
- package/pipeline/multi-agent-refs/rules.md +6 -4
- package/pipeline/multi-agent-refs/setup/repo-discovery.md +2 -2
- package/pipeline/multi-agent-refs/tracker-contract.md +2 -2
- package/pipeline/multi-agent-refs/unattended-contract.md +68 -16
- package/pipeline/rules/figma-pipeline.md +12 -12
- package/pipeline/schemas/agent-state.schema.json +480 -18
- package/pipeline/schemas/analysis-spec.schema.json +4 -4
- package/pipeline/schemas/answer-request.schema.json +24 -0
- package/pipeline/schemas/answer-result.schema.json +28 -0
- package/pipeline/schemas/autopilot-config.schema.json +111 -13
- package/pipeline/schemas/command-parameters.schema.json +99 -0
- package/pipeline/schemas/constitution.schema.json +56 -0
- package/pipeline/schemas/contract-error.schema.json +52 -0
- package/pipeline/schemas/design-check-config.schema.json +5 -1
- package/pipeline/schemas/issues.schema.json +61 -0
- package/pipeline/schemas/launch-plan.schema.json +46 -0
- package/pipeline/schemas/launch-request.schema.json +45 -0
- package/pipeline/schemas/launch.json +61 -0
- package/pipeline/schemas/launch.schema.json +84 -0
- package/pipeline/schemas/phases.json +2 -2
- package/pipeline/schemas/phases.schema.json +68 -0
- package/pipeline/schemas/phone-devices.schema.json +61 -0
- package/pipeline/schemas/phone-signed-request.schema.json +67 -0
- package/pipeline/schemas/plan-critique.schema.json +99 -0
- package/pipeline/schemas/plan-todos.schema.json +7 -7
- package/pipeline/schemas/planning-output.schema.json +5 -0
- package/pipeline/schemas/pr-request.schema.json +46 -0
- package/pipeline/schemas/prefs.schema.json +79 -8
- package/pipeline/schemas/research-output.schema.json +118 -0
- package/pipeline/schemas/review-file-exclusions.schema.json +25 -0
- package/pipeline/schemas/reviewer-output.schema.json +40 -4
- package/pipeline/schemas/run-questions.json +392 -0
- package/pipeline/schemas/run-questions.schema.json +118 -0
- package/pipeline/schemas/runs-index.schema.json +189 -0
- package/pipeline/schemas/scaffold-manifest.schema.json +43 -0
- package/pipeline/schemas/secret-patterns.schema.json +28 -0
- package/pipeline/schemas/stack-adapters.json +527 -0
- package/pipeline/schemas/stack-adapters.schema.json +184 -0
- package/pipeline/schemas/token-budget.json +1 -1
- package/pipeline/schemas/token-budget.schema.json +26 -0
- package/pipeline/schemas/triage-output.schema.json +64 -3
- package/pipeline/schemas/unattended-policy.json +139 -0
- package/pipeline/schemas/unattended-policy.schema.json +73 -0
- package/pipeline/schemas/unattended-profile.json +248 -0
- package/pipeline/schemas/unattended-profile.schema.json +198 -0
- package/pipeline/schemas/worktrees.schema.json +51 -0
- package/pipeline/scripts/README.md +1 -0
- package/pipeline/scripts/_autopilot-config.mjs +130 -0
- package/pipeline/scripts/_autopilot-ops.mjs +567 -0
- package/pipeline/scripts/_autopilot-outcomes.mjs +174 -0
- package/pipeline/scripts/_command-contract.mjs +384 -0
- package/pipeline/scripts/_cost.mjs +40 -0
- package/pipeline/scripts/_notices.mjs +160 -0
- package/pipeline/scripts/_phone-auth.mjs +485 -0
- package/pipeline/scripts/_pre-existing.mjs +294 -0
- package/pipeline/scripts/_redact.mjs +77 -0
- package/pipeline/scripts/_run-paths.mjs +4 -2
- package/pipeline/scripts/_stack-adapter.mjs +678 -0
- package/pipeline/scripts/_stack-routing.mjs +1 -1
- package/pipeline/scripts/agent-guard.py +348 -37
- package/pipeline/scripts/agent-guard.sh +41 -13
- package/pipeline/scripts/analysis-story-tree.mjs +79 -3
- package/pipeline/scripts/answer-question.mjs +181 -0
- package/pipeline/scripts/audit-log-rotate.sh +1 -4
- package/pipeline/scripts/audit-log.sh +4 -4
- package/pipeline/scripts/autopilot-arming.mjs +389 -21
- package/pipeline/scripts/autopilot-awake.mjs +255 -0
- package/pipeline/scripts/autopilot-intake.mjs +137 -36
- package/pipeline/scripts/autopilot-menubar.swift +156 -44
- package/pipeline/scripts/autopilot-publish.mjs +1625 -0
- package/pipeline/scripts/autopilot-runner.mjs +1678 -222
- package/pipeline/scripts/autopilot-status.sh +198 -33
- package/pipeline/scripts/build-lock.sh +120 -0
- package/pipeline/scripts/build-references.mjs +4 -1
- package/pipeline/scripts/build-stack-plugins.mjs +59 -22
- package/pipeline/scripts/capture-flush.sh +1 -1
- package/pipeline/scripts/capture-resume.sh +13 -9
- package/pipeline/scripts/check-derived-drift.mjs +52 -11
- package/pipeline/scripts/commands.mjs +88 -0
- package/pipeline/scripts/constitution.mjs +362 -0
- package/pipeline/scripts/contract-server.mjs +776 -0
- package/pipeline/scripts/cost-analyze.mjs +89 -39
- package/pipeline/scripts/diff-explain.mjs +12 -1
- package/pipeline/scripts/doctor.mjs +77 -28
- package/pipeline/scripts/evidence-gate.mjs +192 -12
- package/pipeline/scripts/feedback-send.mjs +4 -2
- package/pipeline/scripts/gate-ledger.mjs +449 -0
- package/pipeline/scripts/gc-abandoned.sh +132 -13
- package/pipeline/scripts/gen-facts.mjs +31 -15
- package/pipeline/scripts/gen-mode-dispatch.mjs +3 -3
- package/pipeline/scripts/github-ssh-setup.sh +140 -29
- package/pipeline/scripts/graph-mermaid.mjs +4 -1
- package/pipeline/scripts/issues.mjs +236 -0
- package/pipeline/scripts/jira-attach.sh +6 -2
- package/pipeline/scripts/jira-search.sh +4 -3
- package/pipeline/scripts/keychain-save.sh +125 -24
- package/pipeline/scripts/keychain.py +63 -93
- package/pipeline/scripts/launch-request.mjs +747 -0
- package/pipeline/scripts/localize-commands.mjs +4 -10
- package/pipeline/scripts/log-metric.sh +6 -5
- package/pipeline/scripts/maturity-followup.mjs +13 -4
- package/pipeline/scripts/memory-save.sh +25 -0
- package/pipeline/scripts/migrate-prefs.mjs +4 -3
- package/pipeline/scripts/open-questions-gate.mjs +276 -0
- package/pipeline/scripts/phase-tracker.sh +41 -27
- package/pipeline/scripts/phase0-exit-gate.mjs +22 -4
- package/pipeline/scripts/phone-devices.mjs +224 -0
- package/pipeline/scripts/plan-coverage-gate.mjs +200 -66
- package/pipeline/scripts/plan-critique-gate.mjs +591 -0
- package/pipeline/scripts/pr-request.mjs +188 -0
- package/pipeline/scripts/pre-commit-check.sh +115 -4
- package/pipeline/scripts/probe-evidence-capability.sh +44 -5
- package/pipeline/scripts/record-phase.mjs +71 -0
- package/pipeline/scripts/render-agent-log-cost.sh +17 -2
- package/pipeline/scripts/render-cost-summary.sh +1 -1
- package/pipeline/scripts/render-work-summary.sh +1 -1
- package/pipeline/scripts/require-supported-version.sh +4 -1
- package/pipeline/scripts/research-gate.mjs +704 -0
- package/pipeline/scripts/review-decision-gate.mjs +403 -0
- package/pipeline/scripts/routine-registry.mjs +5 -2
- package/pipeline/scripts/runs-index.mjs +135 -27
- package/pipeline/scripts/scaffold-gate.mjs +393 -0
- package/pipeline/scripts/skill-conformance.mjs +25 -8
- package/pipeline/scripts/skill-siblings.mjs +2 -1
- package/pipeline/scripts/smoke-cross-cli-behavior.sh +32 -6
- package/pipeline/scripts/smoke-schema-validation.sh +6 -2
- package/pipeline/scripts/spec-consistency-gate.mjs +469 -0
- package/pipeline/scripts/symbol-existence-gate.mjs +450 -0
- package/pipeline/scripts/test-gap-scan.mjs +40 -2
- package/pipeline/scripts/test-integrity-gate.mjs +20 -4
- package/pipeline/scripts/test-strength.mjs +484 -0
- package/pipeline/scripts/test-summary.mjs +651 -0
- package/pipeline/scripts/triage-memory.mjs +49 -9
- package/pipeline/scripts/unattended_policy.py +2786 -0
- package/pipeline/scripts/uninstall.mjs +10 -10
- package/pipeline/scripts/update-issue-progress.sh +1 -1
- package/pipeline/scripts/usage-identity.mjs +288 -0
- package/pipeline/scripts/usage-register.mjs +185 -65
- package/pipeline/scripts/usage-report.mjs +230 -66
- package/pipeline/scripts/validate-complaint-doc.mjs +28 -10
- package/pipeline/scripts/validate-planning.mjs +6 -0
- package/pipeline/scripts/verify-citations.mjs +151 -38
- package/pipeline/scripts/verify.mjs +58 -18
- package/pipeline/scripts/worktree-prepare.sh +126 -0
- package/pipeline/scripts/worktrees.mjs +124 -0
- package/pipeline/scripts/write-state.mjs +48 -17
- package/pipeline/skills/.skill-manifest.json +222 -226
- package/pipeline/skills/.skills-index.json +77 -88
- package/pipeline/skills/shared/README.md +44 -45
- package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +3 -2
- package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +10 -9
- package/pipeline/skills/shared/core/multi-agent-analysis/SKILL.md +6 -5
- package/pipeline/skills/shared/core/multi-agent-analysis-jira/SKILL.md +11 -3
- package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-autopilot/SKILL.md +4 -3
- package/pipeline/skills/shared/core/multi-agent-autopilot-off/SKILL.md +32 -6
- package/pipeline/skills/shared/core/multi-agent-autopilot-on/SKILL.md +66 -8
- package/pipeline/skills/shared/core/multi-agent-autopilot-status/SKILL.md +27 -9
- package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +7 -4
- package/pipeline/skills/shared/core/multi-agent-complaint-analysis/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-design-check/SKILL.md +7 -5
- package/pipeline/skills/shared/core/multi-agent-diff-explain/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-doctor/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-feedback/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-forget/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-garbage-collect/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-graph/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-issue/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-jira/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-kill/SKILL.md +7 -4
- package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-log/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-manual-test/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-model/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-prune-logs/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-prune-prompts/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-purge/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-refactor/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-research/SKILL.md +35 -0
- package/pipeline/skills/shared/core/multi-agent-resume/SKILL.md +7 -3
- package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +7 -5
- package/pipeline/skills/shared/core/multi-agent-review-analysis/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-review-issue/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-review-jira/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-route-off/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-route-on/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-route-status/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-routines/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-save/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-scaffold/SKILL.md +30 -0
- package/pipeline/skills/shared/core/multi-agent-scan/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-search/SKILL.md +4 -3
- package/pipeline/skills/shared/core/multi-agent-security-review/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-serve/SKILL.md +60 -0
- package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +8 -8
- package/pipeline/skills/shared/core/multi-agent-stack/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-status/SKILL.md +7 -8
- package/pipeline/skills/shared/core/multi-agent-steer/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-store-ready/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +10 -10
- package/pipeline/skills/shared/core/multi-agent-test/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-test-accessibility/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-test-dark-mode/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-test-dynamic-type/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-test-screenshots/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-testflight-validation/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-uninstall/SKILL.md +3 -2
- package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +2 -1
- package/pipeline/skills/shared/external/NOTICE-avdlee-swiftui-agent-skill.md +46 -0
- package/pipeline/skills/shared/external/NOTICE-dimillian-skills.md +9 -3
- package/pipeline/skills/shared/external/NOTICE-paul-hudson-skills.md +54 -0
- package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +9 -11
- package/pipeline/skills/shared/external/NOTICE-vibeship-spawner-skills.md +203 -0
- package/pipeline/skills/shared/external/NOTICE-xcode-build-skills.md +10 -3
- package/pipeline/skills/shared/external/accessibility-compliance-accessibility-audit/SKILL.md +131 -25
- package/pipeline/skills/shared/external/agent-introspection-debugging/SKILL.md +4 -3
- package/pipeline/skills/shared/external/alarmkit/SKILL.md +2 -1
- package/pipeline/skills/shared/external/android-architecture/SKILL.md +85 -76
- package/pipeline/skills/shared/external/android-build-quality-gates/SKILL.md +51 -3
- package/pipeline/skills/shared/external/android-build-quality-gates/references/patterns.md +9 -0
- package/pipeline/skills/shared/external/android-datastore/SKILL.md +4 -3
- package/pipeline/skills/shared/external/android-design-tokens-codegen/SKILL.md +4 -3
- package/pipeline/skills/shared/external/android-jetpack-compose-expert/SKILL.md +106 -181
- package/pipeline/skills/shared/external/android-jetpack-compose-expert/references/patterns.md +147 -0
- package/pipeline/skills/shared/external/android-mvi-viewmodel/SKILL.md +45 -4
- package/pipeline/skills/shared/external/android-performance/SKILL.md +27 -2
- package/pipeline/skills/shared/external/android-performance/references/patterns.md +37 -37
- package/pipeline/skills/shared/external/api-patterns/SKILL.md +111 -67
- package/pipeline/skills/shared/external/api-patterns/references/contract-details.md +128 -0
- package/pipeline/skills/shared/external/api-security-best-practices/SKILL.md +136 -186
- package/pipeline/skills/shared/external/api-security-best-practices/references/abuse-controls.md +140 -0
- package/pipeline/skills/shared/external/api-security-best-practices/references/identity-and-access.md +207 -0
- package/pipeline/skills/shared/external/api-security-best-practices/references/operations.md +66 -0
- package/pipeline/skills/shared/external/api-security-best-practices/references/request-handling.md +175 -0
- package/pipeline/skills/shared/external/app-clips/SKILL.md +2 -0
- package/pipeline/skills/shared/external/app-intents/SKILL.md +2 -0
- package/pipeline/skills/shared/external/app-store-changelog/SKILL.md +4 -3
- package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +2 -0
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +2 -0
- package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +2 -0
- package/pipeline/skills/shared/external/architecture/SKILL.md +106 -39
- package/pipeline/skills/shared/external/architecture/references/adr-and-review.md +76 -0
- package/pipeline/skills/shared/external/authentication/SKILL.md +2 -0
- package/pipeline/skills/shared/external/avkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/background-processing/SKILL.md +2 -1
- package/pipeline/skills/shared/external/backlog/SKILL.md +3 -2
- package/pipeline/skills/shared/external/callkit-voip/SKILL.md +2 -0
- package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/ci-cd-pipelines/SKILL.md +3 -2
- package/pipeline/skills/shared/external/clean-code/SKILL.md +192 -90
- package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +2 -1
- package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/compose-components/SKILL.md +4 -4
- package/pipeline/skills/shared/external/compose-navigation/SKILL.md +22 -22
- package/pipeline/skills/shared/external/compose-navigation/references/patterns.md +10 -10
- package/pipeline/skills/shared/external/compose-testing/SKILL.md +13 -6
- package/pipeline/skills/shared/external/compose-testing/references/patterns.md +59 -59
- package/pipeline/skills/shared/external/contacts-framework/SKILL.md +2 -0
- package/pipeline/skills/shared/external/context-compression/SKILL.md +118 -250
- package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +2 -0
- package/pipeline/skills/shared/external/core-data/SKILL.md +2 -0
- package/pipeline/skills/shared/external/core-motion/SKILL.md +2 -0
- package/pipeline/skills/shared/external/core-nfc/SKILL.md +2 -0
- package/pipeline/skills/shared/external/coreml/SKILL.md +2 -1
- package/pipeline/skills/shared/external/council/SKILL.md +2 -1
- package/pipeline/skills/shared/external/cryptokit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/css-modern/SKILL.md +3 -2
- package/pipeline/skills/shared/external/database-patterns/SKILL.md +3 -2
- package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +2 -0
- package/pipeline/skills/shared/external/debugging-strategies/SKILL.md +130 -20
- package/pipeline/skills/shared/external/debugging-strategies/references/hard-cases.md +54 -0
- package/pipeline/skills/shared/external/device-integrity/SKILL.md +2 -0
- package/pipeline/skills/shared/external/docker-expert/SKILL.md +137 -381
- package/pipeline/skills/shared/external/docker-expert/references/patterns.md +98 -0
- package/pipeline/skills/shared/external/energykit/SKILL.md +2 -1
- package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +3 -1
- package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +2 -2
- package/pipeline/skills/shared/external/fastapi-pro/SKILL.md +116 -185
- package/pipeline/skills/shared/external/fastapi-pro/references/app-structure.md +235 -0
- package/pipeline/skills/shared/external/fastapi-pro/references/testing-and-deployment.md +69 -0
- package/pipeline/skills/shared/external/firebase/SKILL.md +4 -3
- package/pipeline/skills/shared/external/github-actions-templates/SKILL.md +151 -293
- package/pipeline/skills/shared/external/github-actions-templates/references/patterns.md +96 -0
- package/pipeline/skills/shared/external/healthkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/hig-components-content/SKILL.md +69 -72
- package/pipeline/skills/shared/external/hig-components-content/references/content-views.md +111 -0
- package/pipeline/skills/shared/external/hig-components-layout/SKILL.md +77 -86
- package/pipeline/skills/shared/external/hig-components-layout/references/containers.md +98 -0
- package/pipeline/skills/shared/external/hig-components-status/SKILL.md +150 -78
- package/pipeline/skills/shared/external/hig-components-system/SKILL.md +76 -97
- package/pipeline/skills/shared/external/hig-components-system/references/surfaces.md +98 -0
- package/pipeline/skills/shared/external/hig-foundations/SKILL.md +48 -76
- package/pipeline/skills/shared/external/hig-foundations/references/foundations-detail.md +132 -0
- package/pipeline/skills/shared/external/hig-inputs/SKILL.md +147 -106
- package/pipeline/skills/shared/external/hig-patterns/SKILL.md +61 -77
- package/pipeline/skills/shared/external/hig-patterns/references/patterns.md +92 -0
- package/pipeline/skills/shared/external/hig-platforms/SKILL.md +147 -77
- package/pipeline/skills/shared/external/hig-technologies/SKILL.md +61 -121
- package/pipeline/skills/shared/external/hig-technologies/references/technologies.md +108 -0
- package/pipeline/skills/shared/external/homekit-matter/SKILL.md +2 -0
- package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/html-semantic/SKILL.md +3 -2
- package/pipeline/skills/shared/external/humanizer/SKILL.md +2 -1
- package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +2 -0
- package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +2 -1
- package/pipeline/skills/shared/external/ios-coding-standard/references/STANDARD.md +14 -2
- package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +2 -2
- package/pipeline/skills/shared/external/ios-debugger-agent/SKILL.md +4 -3
- package/pipeline/skills/shared/external/ios-localization/SKILL.md +8 -6
- package/pipeline/skills/shared/external/ios-localization/evals/evals.json +2 -2
- package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +11 -11
- package/pipeline/skills/shared/external/ios-module-structure/SKILL.md +2 -1
- package/pipeline/skills/shared/external/ios-networking/SKILL.md +2 -0
- package/pipeline/skills/shared/external/ios-simulator/SKILL.md +2 -0
- package/pipeline/skills/shared/external/kotlin-coroutines-expert/SKILL.md +102 -193
- package/pipeline/skills/shared/external/kotlin-coroutines-expert/references/patterns.md +103 -0
- package/pipeline/skills/shared/external/live-activities/SKILL.md +4 -2
- package/pipeline/skills/shared/external/live-activities/evals/evals.json +2 -2
- package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +7 -9
- package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +3 -3
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +2 -2
- package/pipeline/skills/shared/external/macos-menubar-tuist-app/SKILL.md +4 -3
- package/pipeline/skills/shared/external/macos-spm-app-packaging/SKILL.md +5 -3
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +2 -0
- package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +2 -0
- package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/monorepo-architect/SKILL.md +149 -46
- package/pipeline/skills/shared/external/monorepo-architect/references/patterns.md +70 -0
- package/pipeline/skills/shared/external/musickit-audio/SKILL.md +2 -0
- package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/natural-language/SKILL.md +2 -0
- package/pipeline/skills/shared/external/nextjs-app-router/SKILL.md +3 -2
- package/pipeline/skills/shared/external/nodejs-backend-patterns/SKILL.md +91 -21
- package/pipeline/skills/shared/external/nodejs-backend-patterns/references/runtime-patterns.md +247 -0
- package/pipeline/skills/shared/external/nodejs-backend-patterns/references/testing-and-frameworks.md +57 -0
- package/pipeline/skills/shared/external/observability-engineer/SKILL.md +155 -232
- package/pipeline/skills/shared/external/observability-engineer/references/patterns.md +75 -0
- package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +2 -0
- package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +2 -2
- package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +18 -18
- package/pipeline/skills/shared/external/pdfkit/SKILL.md +2 -1
- package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +2 -0
- package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/permissionkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +2 -1
- package/pipeline/skills/shared/external/push-notifications/SKILL.md +2 -0
- package/pipeline/skills/shared/external/python-patterns/SKILL.md +3 -2
- package/pipeline/skills/shared/external/react-best-practices/SKILL.md +3 -2
- package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +2 -2
- package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +1 -1
- package/pipeline/skills/shared/external/rest-api-design/SKILL.md +3 -2
- package/pipeline/skills/shared/external/retrofit-networking/SKILL.md +7 -7
- package/pipeline/skills/shared/external/retrofit-networking/references/patterns.md +69 -69
- package/pipeline/skills/shared/external/room-database/references/patterns.md +126 -126
- package/pipeline/skills/shared/external/search-first/SKILL.md +2 -1
- package/pipeline/skills/shared/external/security-review/SKILL.md +4 -3
- package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +2 -2
- package/pipeline/skills/shared/external/signal-community/SKILL.md +1 -1
- package/pipeline/skills/shared/external/skill-creator/SKILL.md +2 -1
- package/pipeline/skills/shared/external/speech-recognition/SKILL.md +2 -1
- package/pipeline/skills/shared/external/spm-build-analysis/SKILL.md +2 -0
- package/pipeline/skills/shared/external/storekit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-architecture/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-charts/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-codable/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swift-concurrency-expert/SKILL.md +5 -4
- package/pipeline/skills/shared/external/swift-concurrency-pro/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-language/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swift-security/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-testing/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swift-testing-pro/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swift-testing-pro/references/new-features.md +10 -0
- package/pipeline/skills/shared/external/swiftdata/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftdata-pro/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swiftlint/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-expert-skill/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +3 -1
- package/pipeline/skills/shared/external/swiftui-performance-audit/SKILL.md +5 -4
- package/pipeline/skills/shared/external/swiftui-pro/SKILL.md +2 -1
- package/pipeline/skills/shared/external/swiftui-ui-patterns/SKILL.md +5 -4
- package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +2 -0
- package/pipeline/skills/shared/external/swiftui-view-refactor/SKILL.md +4 -3
- package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/tailwind-css/SKILL.md +3 -2
- package/pipeline/skills/shared/external/testing-backend/SKILL.md +3 -2
- package/pipeline/skills/shared/external/tipkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/typescript-patterns/SKILL.md +3 -2
- package/pipeline/skills/shared/external/vision-framework/SKILL.md +2 -0
- package/pipeline/skills/shared/external/vue-composition/SKILL.md +3 -2
- package/pipeline/skills/shared/external/weatherkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/web-accessibility/SKILL.md +3 -2
- package/pipeline/skills/shared/external/web-performance/SKILL.md +3 -2
- package/pipeline/skills/shared/external/web-testing/SKILL.md +3 -2
- package/pipeline/skills/shared/external/widgetkit/SKILL.md +2 -0
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +1 -1
- package/pipeline/skills/shared/external/xcode-build-benchmark/SKILL.md +2 -0
- package/pipeline/skills/shared/external/xcode-build-fixer/SKILL.md +2 -0
- package/pipeline/skills/shared/external/xcode-build-orchestrator/SKILL.md +2 -0
- package/pipeline/skills/shared/external/xcode-compilation-analyzer/SKILL.md +2 -0
- package/pipeline/skills/shared/external/xcode-project-analyzer/SKILL.md +2 -0
- package/pipeline/skills/skills-index.md +40 -41
- package/docs/token-budget-history.md +0 -24
- package/pipeline/skills/shared/external/agentflow/SKILL.md +0 -199
- package/pipeline/skills/shared/external/android-ui-verification/SKILL.md +0 -66
- package/pipeline/skills/shared/external/api-security-best-practices/references/auth.md +0 -299
- package/pipeline/skills/shared/external/api-security-best-practices/references/input-validation.md +0 -255
- package/pipeline/skills/shared/external/api-security-best-practices/references/rate-limiting.md +0 -167
- package/pipeline/skills/shared/external/closed-loop-delivery/SKILL.md +0 -116
- package/pipeline/skills/shared/external/ios-developer/SKILL.md +0 -216
|
@@ -79,10 +79,10 @@ class BaselineProfileGenerator {
|
|
|
79
79
|
device.findObject(By.text("Search")).click()
|
|
80
80
|
device.waitForIdle()
|
|
81
81
|
|
|
82
|
-
device.findObject(By.res("search_field")).text = "
|
|
82
|
+
device.findObject(By.res("search_field")).text = "London"
|
|
83
83
|
device.waitForIdle()
|
|
84
84
|
|
|
85
|
-
device.findObject(By.res("
|
|
85
|
+
device.findObject(By.res("order_card")).click()
|
|
86
86
|
device.waitForIdle()
|
|
87
87
|
}
|
|
88
88
|
}
|
|
@@ -106,7 +106,7 @@ class BaselineProfileGenerator {
|
|
|
106
106
|
```kotlin
|
|
107
107
|
// Mark a class as truly immutable (all properties never change after construction)
|
|
108
108
|
@Immutable
|
|
109
|
-
data class
|
|
109
|
+
data class OrderUiModel(
|
|
110
110
|
val id: String,
|
|
111
111
|
val route: String,
|
|
112
112
|
val price: String,
|
|
@@ -116,8 +116,8 @@ data class FlightUiModel(
|
|
|
116
116
|
// Mark a class as stable (Compose can track changes via equals)
|
|
117
117
|
@Stable
|
|
118
118
|
data class FilterState(
|
|
119
|
-
val
|
|
120
|
-
val
|
|
119
|
+
val store: String = "",
|
|
120
|
+
val region: String = "",
|
|
121
121
|
val date: LocalDate? = null,
|
|
122
122
|
)
|
|
123
123
|
```
|
|
@@ -132,19 +132,19 @@ implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8")
|
|
|
132
132
|
|
|
133
133
|
// Usage
|
|
134
134
|
@Immutable
|
|
135
|
-
data class
|
|
136
|
-
val
|
|
135
|
+
data class OrderListUiState(
|
|
136
|
+
val orders: ImmutableList<OrderUiModel> = persistentListOf(),
|
|
137
137
|
val isLoading: Boolean = false,
|
|
138
138
|
)
|
|
139
139
|
|
|
140
140
|
// Convert in ViewModel
|
|
141
|
-
val uiState: StateFlow<
|
|
142
|
-
.map {
|
|
143
|
-
|
|
144
|
-
|
|
141
|
+
val uiState: StateFlow<OrderListUiState> = repository.getOrders()
|
|
142
|
+
.map { orders ->
|
|
143
|
+
OrderListUiState(
|
|
144
|
+
orders = orders.map(::toUiModel).toImmutableList(),
|
|
145
145
|
)
|
|
146
146
|
}
|
|
147
|
-
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000),
|
|
147
|
+
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), OrderListUiState())
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
### Strong Skipping Mode (Kotlin 2.0+)
|
|
@@ -224,17 +224,17 @@ efficiently diff items.
|
|
|
224
224
|
// CORRECT: stable key from item ID
|
|
225
225
|
LazyColumn {
|
|
226
226
|
items(
|
|
227
|
-
items =
|
|
228
|
-
key = {
|
|
229
|
-
) {
|
|
230
|
-
|
|
227
|
+
items = orders,
|
|
228
|
+
key = { order -> order.id },
|
|
229
|
+
) { order ->
|
|
230
|
+
OrderCard(order = order)
|
|
231
231
|
}
|
|
232
232
|
}
|
|
233
233
|
|
|
234
234
|
// WRONG: no key -- full list diff on every change
|
|
235
235
|
LazyColumn {
|
|
236
|
-
items(
|
|
237
|
-
|
|
236
|
+
items(orders) { order ->
|
|
237
|
+
OrderCard(order = order)
|
|
238
238
|
}
|
|
239
239
|
}
|
|
240
240
|
```
|
|
@@ -248,14 +248,14 @@ LazyColumn {
|
|
|
248
248
|
key = { it.id },
|
|
249
249
|
contentType = { item ->
|
|
250
250
|
when (item) {
|
|
251
|
-
is FeedItem.
|
|
251
|
+
is FeedItem.Order -> "order"
|
|
252
252
|
is FeedItem.Hotel -> "hotel"
|
|
253
253
|
is FeedItem.Ad -> "ad"
|
|
254
254
|
}
|
|
255
255
|
},
|
|
256
256
|
) { item ->
|
|
257
257
|
when (item) {
|
|
258
|
-
is FeedItem.
|
|
258
|
+
is FeedItem.Order -> OrderCard(item)
|
|
259
259
|
is FeedItem.Hotel -> HotelCard(item)
|
|
260
260
|
is FeedItem.Ad -> AdBanner(item)
|
|
261
261
|
}
|
|
@@ -270,16 +270,16 @@ similar to RecyclerView's view type system.
|
|
|
270
270
|
|
|
271
271
|
```kotlin
|
|
272
272
|
// WRONG: formatting on every recomposition
|
|
273
|
-
items(
|
|
273
|
+
items(orders, key = { it.id }) { order ->
|
|
274
274
|
val formatted = SimpleDateFormat("HH:mm", Locale.getDefault())
|
|
275
|
-
.format(Date(
|
|
275
|
+
.format(Date(order.placedAt))
|
|
276
276
|
Text(formatted)
|
|
277
277
|
}
|
|
278
278
|
|
|
279
279
|
// CORRECT: precompute in ViewModel or UiModel
|
|
280
|
-
data class
|
|
280
|
+
data class OrderUiModel(
|
|
281
281
|
val id: String,
|
|
282
|
-
val
|
|
282
|
+
val formattedPlacedAt: String, // precomputed
|
|
283
283
|
)
|
|
284
284
|
```
|
|
285
285
|
|
|
@@ -292,8 +292,8 @@ LazyColumn(
|
|
|
292
292
|
// For custom behavior:
|
|
293
293
|
flingBehavior = ScrollableDefaults.flingBehavior(),
|
|
294
294
|
) {
|
|
295
|
-
items(
|
|
296
|
-
|
|
295
|
+
items(orders, key = { it.id }) { order ->
|
|
296
|
+
OrderCard(order = order)
|
|
297
297
|
}
|
|
298
298
|
}
|
|
299
299
|
```
|
|
@@ -448,7 +448,7 @@ class StartupBenchmark {
|
|
|
448
448
|
pressHome()
|
|
449
449
|
startActivityAndWait()
|
|
450
450
|
|
|
451
|
-
val list = device.findObject(By.res("
|
|
451
|
+
val list = device.findObject(By.res("order_list"))
|
|
452
452
|
list.setGestureMargin(device.displayWidth / 5)
|
|
453
453
|
list.fling(Direction.DOWN)
|
|
454
454
|
device.waitForIdle()
|
|
@@ -516,7 +516,7 @@ implementation("io.coil-kt:coil-compose:2.7.0")
|
|
|
516
516
|
|
|
517
517
|
// Composable
|
|
518
518
|
@Composable
|
|
519
|
-
fun
|
|
519
|
+
fun OrderImage(imageUrl: String, modifier: Modifier = Modifier) {
|
|
520
520
|
AsyncImage(
|
|
521
521
|
model = ImageRequest.Builder(LocalContext.current)
|
|
522
522
|
.data(imageUrl)
|
|
@@ -524,7 +524,7 @@ fun FlightImage(imageUrl: String, modifier: Modifier = Modifier) {
|
|
|
524
524
|
.memoryCacheKey(imageUrl)
|
|
525
525
|
.diskCacheKey(imageUrl)
|
|
526
526
|
.build(),
|
|
527
|
-
contentDescription = "
|
|
527
|
+
contentDescription = "Order image",
|
|
528
528
|
modifier = modifier,
|
|
529
529
|
contentScale = ContentScale.Crop,
|
|
530
530
|
)
|
|
@@ -576,10 +576,10 @@ AsyncImage(
|
|
|
576
576
|
```kotlin
|
|
577
577
|
AsyncImage(
|
|
578
578
|
model = imageUrl,
|
|
579
|
-
contentDescription = "
|
|
580
|
-
placeholder = painterResource(R.drawable.
|
|
581
|
-
error = painterResource(R.drawable.
|
|
582
|
-
fallback = painterResource(R.drawable.
|
|
579
|
+
contentDescription = "Brand logo",
|
|
580
|
+
placeholder = painterResource(R.drawable.placeholder_brand),
|
|
581
|
+
error = painterResource(R.drawable.error_brand),
|
|
582
|
+
fallback = painterResource(R.drawable.default_brand),
|
|
583
583
|
modifier = Modifier
|
|
584
584
|
.size(48.dp)
|
|
585
585
|
.clip(CircleShape),
|
|
@@ -592,7 +592,7 @@ AsyncImage(
|
|
|
592
592
|
|
|
593
593
|
```kotlin
|
|
594
594
|
@Composable
|
|
595
|
-
fun
|
|
595
|
+
fun OrderList(orders: List<Order>) {
|
|
596
596
|
val listState = rememberLazyListState()
|
|
597
597
|
|
|
598
598
|
// Only recalculates when the derived condition changes
|
|
@@ -602,7 +602,7 @@ fun FlightList(flights: List<Flight>) {
|
|
|
602
602
|
|
|
603
603
|
Box {
|
|
604
604
|
LazyColumn(state = listState) {
|
|
605
|
-
items(
|
|
605
|
+
items(orders, key = { it.id }) { OrderCard(it) }
|
|
606
606
|
}
|
|
607
607
|
|
|
608
608
|
if (showScrollToTop) {
|
|
@@ -640,12 +640,12 @@ fun DateDisplay(timestamp: Long) {
|
|
|
640
640
|
```kotlin
|
|
641
641
|
@HiltViewModel
|
|
642
642
|
class SearchViewModel @Inject constructor(
|
|
643
|
-
private val searchUseCase:
|
|
643
|
+
private val searchUseCase: SearchOrdersUseCase,
|
|
644
644
|
) : ViewModel() {
|
|
645
645
|
|
|
646
646
|
private val searchQuery = MutableStateFlow("")
|
|
647
647
|
|
|
648
|
-
val searchResults: StateFlow<List<
|
|
648
|
+
val searchResults: StateFlow<List<Order>> = searchQuery
|
|
649
649
|
.debounce(300) // Wait 300ms after last keystroke
|
|
650
650
|
.distinctUntilChanged()
|
|
651
651
|
.filter { it.length >= 2 }
|
|
@@ -1,73 +1,117 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: api-patterns
|
|
3
|
-
description: "API
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
description: "Choosing an API style (REST, GraphQL, gRPC, webhooks, events) and the contracts every style needs: versioning, cursor pagination, idempotency keys, RFC 9457 errors. Use when deciding how two systems talk or how a contract evolves."
|
|
4
|
+
metadata:
|
|
5
|
+
risk: safe
|
|
6
|
+
source: multi-agent-pipeline
|
|
7
|
+
date_added: "2026-09-25"
|
|
8
|
+
not-for: rest-api-design
|
|
7
9
|
---
|
|
8
10
|
|
|
9
11
|
# API Patterns
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
|
36
|
-
|
|
37
|
-
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
13
|
+
An interface outlives the code on both sides of it. Clients ship on their own
|
|
14
|
+
schedule, mobile builds stay installed for years, and partner integrations get
|
|
15
|
+
written once and forgotten. The decisions here are the ones that are expensive
|
|
16
|
+
to reverse, so make them deliberately and write the reasoning down.
|
|
17
|
+
|
|
18
|
+
This skill covers the choice of style and the contracts that apply whatever
|
|
19
|
+
style wins. REST mechanics (URLs, verbs, status codes, cache headers, OpenAPI)
|
|
20
|
+
live in `rest-api-design`; security controls live in `api-security-best-practices`.
|
|
21
|
+
|
|
22
|
+
## 1. Start from the consumers, not the technology
|
|
23
|
+
|
|
24
|
+
Answer these before naming a style:
|
|
25
|
+
|
|
26
|
+
- **Who calls it?** Your own frontend, other internal services, third parties
|
|
27
|
+
you do not control, or devices that update rarely.
|
|
28
|
+
- **What is the interaction shape?** Ask-and-answer, a long-running job, a
|
|
29
|
+
notification that something happened, or a continuous feed.
|
|
30
|
+
- **Who owns change?** If one team owns both ends, coupling is cheap. If the
|
|
31
|
+
caller is outside your release train, every change is a negotiation.
|
|
32
|
+
- **What does the network look like?** Browser, mobile on flaky links,
|
|
33
|
+
service mesh inside one data centre.
|
|
34
|
+
|
|
35
|
+
## 2. Choosing a style
|
|
36
|
+
|
|
37
|
+
| Situation | Reasonable default | Why |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| Public or partner API, broad tooling expected | REST over HTTP with an OpenAPI document | Every language and proxy understands it; caching works |
|
|
40
|
+
| One product team owns a rich client with many screens pulling nested data | GraphQL | Client picks fields; one round trip per screen |
|
|
41
|
+
| Internal service-to-service calls with strict latency budgets | gRPC with protobuf | Typed contracts, code generation, HTTP/2 streaming |
|
|
42
|
+
| TypeScript monorepo where server and client ship together | tRPC or a shared schema package | Types flow end to end without a separate IDL |
|
|
43
|
+
| "Tell me when X happens" to an external party | Webhooks | Caller does not poll; you push on change |
|
|
44
|
+
| Many internal consumers reacting to the same fact | Events on a log or broker (Kafka, NATS, SQS/SNS) | Producers stay unaware of consumers |
|
|
45
|
+
| Work that takes longer than a request should | Accept, return a job resource, then poll or notify | Keeps request timeouts honest |
|
|
46
|
+
|
|
47
|
+
Mixing is normal: a public REST API, gRPC between internal services, and an
|
|
48
|
+
event stream for side effects is a common and healthy shape. What goes wrong is
|
|
49
|
+
picking GraphQL or gRPC for a public surface because it is fashionable, then
|
|
50
|
+
rebuilding caching, auth and tooling that REST gave for free.
|
|
51
|
+
|
|
52
|
+
### GraphQL specifics worth deciding up front
|
|
53
|
+
|
|
54
|
+
- Depth and complexity limits, or one query can fan out into thousands of
|
|
55
|
+
resolver calls.
|
|
56
|
+
- A batching layer (DataLoader or equivalent) so a list of 50 orders does not
|
|
57
|
+
run 50 customer lookups.
|
|
58
|
+
- Persisted queries for production clients, which also shrink the attack surface.
|
|
59
|
+
- Errors: GraphQL returns 200 with an `errors` array; decide which failures are
|
|
60
|
+
field-level and which reject the whole operation.
|
|
61
|
+
|
|
62
|
+
### gRPC specifics
|
|
63
|
+
|
|
64
|
+
- Never reuse or renumber a protobuf field tag; mark removed ones `reserved`.
|
|
65
|
+
- Set deadlines on every call and propagate them downstream.
|
|
66
|
+
- Browsers need gRPC-Web or Connect; plan a gateway if a web client is coming.
|
|
67
|
+
|
|
68
|
+
## 3. Evolving a contract
|
|
69
|
+
|
|
70
|
+
Additive changes (optional fields, new endpoints or event types, enum values
|
|
71
|
+
clients were told to tolerate) ship without a version; removals, renames, type
|
|
72
|
+
or meaning changes need a migration plan. Prefer additive-only, then dated
|
|
73
|
+
versions, then a path major version. Announce deprecation with `Deprecation`
|
|
74
|
+
and `Sunset` headers, measure remaining callers, and check event schema
|
|
75
|
+
compatibility in CI. Details: `references/contract-details.md`.
|
|
76
|
+
|
|
77
|
+
## 4. Contracts every style needs
|
|
78
|
+
|
|
79
|
+
Load `references/contract-details.md` for examples. The rules:
|
|
80
|
+
|
|
81
|
+
- **Pagination**: opaque cursor over the sort key plus a unique tiebreaker,
|
|
82
|
+
server-capped `limit`, no total count unless it is cheap; offset paging only
|
|
83
|
+
for small, static data.
|
|
84
|
+
- **Idempotency**: non-idempotent writes accept an `Idempotency-Key` scoped to
|
|
85
|
+
the caller. Replay the stored result for a completed key, `409` while it is
|
|
86
|
+
still running, `422` for the same key with a different body; store key and
|
|
87
|
+
result in the side effect's transaction and expire them after a stated window.
|
|
88
|
+
Consumers deduplicate on the event id.
|
|
89
|
+
- **Errors**: one RFC 9457 problem-details shape (`application/problem+json`)
|
|
90
|
+
with a stable `type`, field errors as JSON Pointers, a request id, and no
|
|
91
|
+
internals. gRPC uses canonical codes plus `google.rpc` details; events go to a
|
|
92
|
+
dead-letter destination with the reason.
|
|
93
|
+
- **Webhooks**: HMAC-signed timestamp plus body with replay rejection, retries
|
|
94
|
+
with backoff and jitter then parking, a documented thin or full payload, and
|
|
95
|
+
replay on request.
|
|
96
|
+
|
|
97
|
+
## 5. Checklist before publishing a contract
|
|
98
|
+
|
|
99
|
+
- [ ] Style chosen from consumer and interaction shape, reasoning recorded (ADR).
|
|
100
|
+
- [ ] Machine-readable schema exists: OpenAPI, GraphQL SDL, `.proto`, or event schema.
|
|
101
|
+
- [ ] Unknown fields and enum values are tolerated by clients, and documented as such.
|
|
102
|
+
- [ ] List endpoints paginate with a capped cursor.
|
|
103
|
+
- [ ] Non-idempotent writes accept an idempotency key.
|
|
104
|
+
- [ ] Every error uses the shared problem shape with a stable `type`.
|
|
105
|
+
- [ ] Deprecation policy is written down with a minimum notice period.
|
|
106
|
+
- [ ] A contract test or breaking-change check runs in CI.
|
|
107
|
+
|
|
108
|
+
## References
|
|
109
|
+
|
|
110
|
+
- `references/contract-details.md`: pagination, idempotency, problem-details and webhook examples in full.
|
|
111
|
+
|
|
112
|
+
## Related skills
|
|
113
|
+
|
|
114
|
+
- `rest-api-design`: URLs, methods, status codes, caching headers, OpenAPI.
|
|
115
|
+
- `api-security-best-practices`: authentication, authorization, rate limits.
|
|
116
|
+
- `architecture`: recording the decision as an ADR.
|
|
117
|
+
- `nodejs-backend-patterns`, `fastapi-pro`: implementing the chosen contract.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# API contract details
|
|
2
|
+
|
|
3
|
+
Versioning rules and worked examples for the pagination, idempotency, error-shape and webhook rules summarised in SKILL.md.
|
|
4
|
+
|
|
5
|
+
## Contents
|
|
6
|
+
|
|
7
|
+
- Evolving a contract
|
|
8
|
+
- Pagination
|
|
9
|
+
- Idempotency for retried writes
|
|
10
|
+
- One error shape everywhere
|
|
11
|
+
- Webhooks done properly
|
|
12
|
+
|
|
13
|
+
## Evolving a contract
|
|
14
|
+
|
|
15
|
+
Treat every published field as a promise. Additive change is almost always safe;
|
|
16
|
+
removal, renaming and changing meaning are not.
|
|
17
|
+
|
|
18
|
+
Safe without a new version:
|
|
19
|
+
|
|
20
|
+
- adding an optional request field or a new response field;
|
|
21
|
+
- adding a new endpoint, RPC or event type;
|
|
22
|
+
- adding an enum value, **only if** clients were told to tolerate unknown values.
|
|
23
|
+
|
|
24
|
+
Breaking, needs a migration plan:
|
|
25
|
+
|
|
26
|
+
- removing or renaming a field, or making an optional field required;
|
|
27
|
+
- changing a type, unit or format (`price` from cents to decimal string);
|
|
28
|
+
- changing default behaviour or the meaning of a status.
|
|
29
|
+
|
|
30
|
+
Versioning mechanics, from lightest to heaviest:
|
|
31
|
+
|
|
32
|
+
1. **No explicit version, additive only.** Works longer than people expect.
|
|
33
|
+
2. **Dated versions** pinned per client (`Api-Version: 2026-06-01`), with the
|
|
34
|
+
server translating older shapes. Good for public APIs with many integrators.
|
|
35
|
+
3. **Major version in the path** (`/v2/orders`). Simple to route and reason
|
|
36
|
+
about, costly to maintain two copies.
|
|
37
|
+
|
|
38
|
+
Whatever the scheme, publish a deprecation window, emit a `Deprecation` and
|
|
39
|
+
`Sunset` header (RFC 9745 / RFC 8594) on retiring endpoints, and measure who is
|
|
40
|
+
still calling before you switch anything off.
|
|
41
|
+
|
|
42
|
+
For events, the same rules apply to the payload schema. Keep a schema registry
|
|
43
|
+
or a versioned schema file and run a compatibility check in CI.
|
|
44
|
+
|
|
45
|
+
## Pagination
|
|
46
|
+
|
|
47
|
+
Offset pagination (`?page=7`) is easy and wrong for data that changes: rows
|
|
48
|
+
shift between requests and deep pages get slow. Prefer an opaque cursor.
|
|
49
|
+
|
|
50
|
+
```http
|
|
51
|
+
GET /products?limit=50&after=eyJpZCI6IjAxSjhRIn0
|
|
52
|
+
|
|
53
|
+
200 OK
|
|
54
|
+
{
|
|
55
|
+
"data": [ ... ],
|
|
56
|
+
"page": { "next": "eyJpZCI6IjAxSjk0In0", "hasMore": true }
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
- The cursor encodes the sort key plus a unique tiebreaker (`created_at`, `id`)
|
|
61
|
+
and is base64 so clients treat it as opaque.
|
|
62
|
+
- Cap `limit` on the server; ignore or clamp values above it.
|
|
63
|
+
- Do not promise a total count unless it is cheap; counting a large table on
|
|
64
|
+
every page request is a common production hotspot.
|
|
65
|
+
- Streaming or long-lived exports are a job, not a very large page.
|
|
66
|
+
|
|
67
|
+
## Idempotency for retried writes
|
|
68
|
+
|
|
69
|
+
Networks drop responses, not just requests. A client that times out on
|
|
70
|
+
`POST /orders` cannot know if the order exists. Give it a way to retry safely.
|
|
71
|
+
|
|
72
|
+
```http
|
|
73
|
+
POST /orders
|
|
74
|
+
Idempotency-Key: 5f1c2d0e-8b7a-4c77-9a61-0d3f6c1b2a90
|
|
75
|
+
Content-Type: application/json
|
|
76
|
+
|
|
77
|
+
{ "productId": "p_812", "quantity": 2 }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Server behaviour:
|
|
81
|
+
|
|
82
|
+
1. Look up the key scoped to the caller. If a completed result exists, return it
|
|
83
|
+
unchanged, including the original status code.
|
|
84
|
+
2. If a request with that key is still running, return `409 Conflict` so the client backs off.
|
|
85
|
+
3. If the same key arrives with a different body, reject it with `422`.
|
|
86
|
+
4. Store the key and result in the same transaction as the side effect, and
|
|
87
|
+
expire keys after a stated window (24 hours is typical).
|
|
88
|
+
|
|
89
|
+
`PUT` and `DELETE` are idempotent by definition, but only if your handler is.
|
|
90
|
+
Webhook and event consumers need the same property: deduplicate on the event id,
|
|
91
|
+
because at-least-once delivery means duplicates will arrive.
|
|
92
|
+
|
|
93
|
+
## One error shape everywhere
|
|
94
|
+
|
|
95
|
+
Use RFC 9457 problem details for HTTP APIs. Clients then write one error
|
|
96
|
+
handler instead of one per endpoint.
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"type": "https://api.example.com/problems/insufficient-stock",
|
|
101
|
+
"title": "Not enough stock",
|
|
102
|
+
"status": 409,
|
|
103
|
+
"detail": "Only 1 unit of product p_812 is available.",
|
|
104
|
+
"instance": "/orders/req_01J9Z",
|
|
105
|
+
"errors": [{ "pointer": "/quantity", "detail": "must be at most 1" }]
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- `type` is a stable identifier clients can branch on; `title` is for humans.
|
|
110
|
+
- Put field-level validation failures in an extension member (`errors` above)
|
|
111
|
+
using JSON Pointers into the request body.
|
|
112
|
+
- Never leak stack traces, SQL or internal hostnames in `detail`.
|
|
113
|
+
- Include a request or trace id so support can find the log line.
|
|
114
|
+
- Serve it as `application/problem+json`.
|
|
115
|
+
|
|
116
|
+
For gRPC, map to canonical status codes and attach `google.rpc` error details;
|
|
117
|
+
for events, a failed consumer moves the message to a dead-letter destination
|
|
118
|
+
with the reason attached.
|
|
119
|
+
|
|
120
|
+
## Webhooks done properly
|
|
121
|
+
|
|
122
|
+
- Sign every delivery (HMAC-SHA256 over timestamp plus body) and document how to
|
|
123
|
+
verify it; reject deliveries older than a few minutes to stop replay.
|
|
124
|
+
- Retry with exponential backoff and jitter for a bounded period, then park the
|
|
125
|
+
delivery and surface it in a dashboard.
|
|
126
|
+
- Send a thin payload (event type, id, resource URL) or a full snapshot, and say
|
|
127
|
+
which; thin payloads avoid stale data at the cost of a follow-up call.
|
|
128
|
+
- Let integrators replay past deliveries; they will lose some.
|