本文へ移動
BlackOps1.xは試験的なバージョンです。Production Readyは2.xを予定しています。Releases
BlackOps
Esc
navigateopen⌘Jpreview
このページの内容

Troubleshooting

症状から原因、確認、修正へ進み、Operation、Storage、Observabilityの復旧を完了する。

問題が起きたら、表示された症状だけで判断せず、原因候補を確認してから修正します。Operation IDは一つの処理を受付からTerminal Stateまで追跡する識別子です。出力やLogへCredentialを貼り付けないでください。

Taskの実行順を先に確認する場合は、TestingDeploymentConsoleCommandOutboxBlackOps CLIへ戻ります。ここではFailureの分類、確認コマンド、安全な出力境界だけを扱います。

database:seedがArtifact Errorになる

症状: Database seeding artifacts are unavailable.またはDatabase seeding runtime could not be resolved.が表示されます。

考えられる原因: Root Seederを追加・変更した後にbuild:compileしていない、Application Build IDが変わった、またはCompiled Containerが欠落しています。

確認方法: php blackops database:statusでMigration状態を確認し、php blackops build:compileのExit Codeと生成されたArtifactの存在を確認します。

修正方法: Migrationを適用し、現在のSourceと設定でBuildしてからSeedを再実行します。

php blackops database:migrate
php blackops build:compile
php blackops database:seed

Database seeding failed.の場合はApplication Seederが失敗しています。CommandはSQL、投入値、Credential、Throwableを意図的に表示しません。Application側の安全なLogとDatabase状態を確認し、Transaction、Conflict、再実行方針を修正してください。

Typed Self-handled Signature Error

症状: build:compileがTyped Self-handled handle()のSignature Errorを表示します。

考えられる原因: handle()がPublic/Non-staticでない、第一引数が具象OperationValueでない、第二引数がExecutionContextでない、Return Typeが具象Outcomeまたはvoidでない、あるいはNullable/Union/Optional Parameterを使っています。Typed標準形と#[HandledBy]を同時に指定した場合もAmbiguousとして失敗します。

確認方法: Operation Classのhandle()を確認し、次のコマンドでもう一度Compileします。

php blackops build:compile -vvv

修正方法: public function handle(ConcreteValue $value): ConcreteOutcome、またはContextが必要な場合だけpublic function handle(ConcreteValue $value, ExecutionContext $context): ConcreteOutcomeへ直します。Typed標準形から#[Accepts]#[Returns]OperationHandlerを外します。

401にOperation IDがある場合とない場合

症状: Quickstartの/welcomeが401を返し、Header欠落時はOperation IDがあるのに、不正なX-Sample-TokenではOperation IDがありません。

考えられる原因: Header欠落はAnonymous AuthenticationとしてOperationへ進み、#[Authorize]がLifecycle内でRejectします。不正HeaderはAuthentication MiddlewareがOperation受付前に停止します。

確認方法: Local Example Tokenで3経路を比較します。CredentialをLogへ出力しないでください。

curl -i http://127.0.0.1:8080/welcome
curl -i -H 'X-Sample-Token: invalid' http://127.0.0.1:8080/welcome
curl -i -H 'X-Sample-Token: local-example' http://127.0.0.1:8080/welcome

修正方法: Localでは.envへ空でないSAMPLE_API_TOKENを明示し、Headerと一致させます。未設定または空の設定は既知値へFallbackせずRuntime構成Errorになります。ProductionでSample Token方式を使い続けず、ApplicationのAuthenticator、Secret管理、Actor/Permission検索へ置き換えます。Header値をOperation Valueへ追加して解決しないでください。

Operation Discovery/Manifest未登録

症状: operation:listへ新しいOperationが出ず、HTTP Routeも404になります。

考えられる原因: Sourceがconfig/operations.phpのDiscovery Root外にある、ClassがComposer Autoload対象外である、Operationを実装していない、またはBuild後にSourceだけを変更しています。ManifestはBuild時に生成するRuntime検索Artifactです。

確認方法: Discovery結果とConfigを確認します。

php blackops operation:list
php -r '$config = require "config/operations.php"; var_export($config["discovery"] ?? null); echo PHP_EOL;'

修正方法: OperationをDiscovery Root配下へ置き、Composer Autoloadを更新してから再Buildします。通常のApplication FeatureをOperationProviderへ手動列挙しないでください。PackageやRoot外SourceだけProviderで登録します。

Build Artifact不在/Build ID不一致

症状: HTTP、Worker、またはConsole CommandがArtifact不在、Format不正、Build ID不一致で起動しません。

考えられる原因: var/build/を生成していない、別ReleaseのArtifactをDeployした、またはAPP_BUILD_IDを変えた後に再Buildしていません。Production RuntimeはSource DiscoveryへFallbackしません。

確認方法: Configured PathとFileを確認し、現在のSourceでCompileできるか試します。

php -r '$config = require "config/app.php"; var_export($config["build"] ?? null); echo PHP_EOL;'
ls -l var/build/operations.php var/build/http.php var/build/container.php
php blackops build:compile

修正方法: Deploy対象のSource、Dependency、Configを同じBuild工程へ固定し、その工程で3 Artifactを再生成します。古いArtifactを別ReleaseへCopyしません。

Frontend Contract ArtifactがInvalid/Stale

症状: frontend:generateまたはfrontend:checkがContract Artifact不正として失敗します。

考えられる原因: var/build/frontend.phpがない、Schemaが古い、Operation/HTTP/Frontend ManifestのBuild IDが違う、またはPHP Operation変更後に再Buildしていません。Frontend CommandはSource Reflectionやbuild:compileへFallbackしません。

確認方法: Backend Artifactを同じApplication Build IDで作り直し、Commandを順番どおり実行します。CredentialやArtifact PayloadをErrorへ貼り付けないでください。

php blackops build:compile
php blackops frontend:generate
php blackops frontend:check

修正方法: Source、Composer Dependency、APP_BUILD_IDconfig/app.phpを同じBuild工程へ固定し、その工程でArtifactを再生成します。別Releaseのfrontend.phpやGenerated TreeをCopyしません。

Frontend Generated TreeがMissing/Drift

症状: frontend:checkがExit 1でmissingまたはhas driftを表示します。

考えられる原因: resources/js/blackops/をまだ生成していない、生成後にPHP Contractが変わった、Generated Fileを手動編集/追加した、または別Build IDのTreeが残っています。

確認方法: CheckはRead-onlyなので、実行前後のApplication Sourceを変更せず状態を分類できます。

php blackops frontend:check
echo $?

修正方法: Application-owned resources/js/application/を編集し、Generated resources/js/blackops/は編集しません。現在のArtifactからphp blackops frontend:generateを実行し、続けてCheckします。Non-marker DirectoryやSymlinkを強制削除せず、所有者を確認してから別Pathへ退避します。

Generated TypeScriptがCompileできない

症状: pnpm testまたはtscがGenerated OperationのImport、Value Input、Result Narrowingで型Errorを返します。

考えられる原因: Generate前、古いGenerated Tree、手書きのURL/Response型との競合、OperationValue変更にApplication-owned Consumerが追従していない、またはLockfileと異なるTypeScriptを使っています。

確認方法: Frozen LockfileとCanonical Chainを使い、最初にDriftを除外します。

pnpm install --frozen-lockfile
php blackops build:compile
php blackops frontend:generate
php blackops frontend:check
pnpm test

修正方法: Generated FileをCastやanyで隠さず、PHP OperationValue/OutcomeまたはApplication-owned Consumer Sourceを修正して再生成します。Unsupported Collection/DTO/Enumを無理にScalarへ見せず、現行Supported Typeへ戻します。

.fetch()がTransport Resultを返す

症状: .fetch()missing_fetchinvalid_base_urlnetwork_errorabortedunexpected_responseのTransport Resultを返します。

考えられる原因: RuntimeにglobalThis.fetchがなくInjected Fetchもない、Base URLがHTTP/HTTPS Origin形式でない、Network/Abortが発生した、またはResponseのStatus/Content-Type/JSON ShapeがCompiled Contractと一致しません。

確認方法: result.kind === 'transport'と安定したresult.error.codeだけを確認し、Raw Response Body、Token、Thrown Error MessageをLogへ出さないでください。SSR/Node/Testでは呼出単位のfetchbaseUrlを明示します。

const result = await ShowWelcome.fetch({}, { baseUrl, fetch: runtimeFetch });

if (!result.ok && result.kind === 'transport') {
  const safeCode: string = result.error.code;
  void safeCode;
}

修正方法: RuntimeへWeb Fetch互換実装を注入し、安全なHTTP/HTTPS Base URLを使います。unexpected_responseではServerの公開Response ContractとGenerated ClientのBuild IDを揃えます。Raw BodyをResultへ追加するPatchやGlobal Mutable Credential Clientで回避しません。

Deferred HTTPが202だがOutcomeがない

症状: HTTPは202 AcceptedとOperation IDを返しますが、Outcomeが作られません。

考えられる原因: Workerを起動していない、Workerが別Database/Schemaを見ている、Retry Delay前である、またはProcess SupervisorがWorkerを停止しています。

確認方法: 同じEnvironmentでWorkerを1 Loopだけ実行し、対象Operation IDのJournalにoperation.acceptedattempt.startedattempt.retry_scheduled、Terminal Eventがあるか確認します。

curl -i -H 'X-Sample-Token: local-example' \
  http://127.0.0.1:8080/operations/<operation-id>
php blackops worker:run --iterations=1 --idle-sleep-milliseconds=1

<operation-id>は202 Responseの値へ置き換えます。Worker未起動ならStatusはacceptedのままです。var/log/journal.jsonlはHTTP ProcessのObserved Projectionなので、Worker完了を待つSourceには使いません。

修正方法: HTTPとWorkerへ同じDatabase/Schema/Build Artifactを渡し、常駐WorkerをProcess ManagerまたはCompose Worker Profileで監督します。Retry Scheduledの場合はDelay後のAttemptを待ちます。

Statusが404 operation_unavailableを返す

症状: 202で受け取ったOperation IDをGET /operations/{operationId}へ渡しても404になります。

考えられる原因: IDがUnknown、OperationStatusAuthorizerが未BindingまたはDeny、Current ActorとOrigin Actorが不一致、あるいはSubject自体がRetentionで完全削除されています。Frameworkは存在とDenyを区別させません。

確認方法: 同じCredentialを使っているか、Application Service ProviderがOperationStatusAuthorizer::classをApplication実装へBindingしているかを確認します。Operation IDやActor IDだけをLogへ追加しないでください。

修正方法: ApplicationのStatus PolicyでCurrent Actor、Origin Actor、Tenant/Resource関係を評価します。Operation IDを知っていることだけをAllow条件にせず、Framework既定Denyを無効化する全許可Policyも置きません。QuickstartのSame-origin PolicyはLocal ExampleなのでProduction Policyへ置き換えます。

Statusが410 operation_expiredを返す

症状: 以前は取得できたOperationが410になります。

考えられる原因: AuthorizerはAllowしましたが、Terminal DetailまたはOutcomeがRetentionで削除され、Purge Auditから期限切れを証明できました。

確認方法: retention:planと承認済みRetention Policyを確認します。Unknown/Denyは404なので、410を認可判定の代わりに使いません。

修正方法: 必要な保持期間をApplicationのPolicyとして見直します。削除済みCanonical PayloadをStatus ResponseやBackupから無断で復元せず、Legal Hold、Access Control、Purge承認を運用します。

.wait()poll_timeoutを返す

症状: .wait()がTerminal StateではなくTransport Resultのpoll_timeoutを返します。

考えられる原因: Worker未起動、Retry Delay中、処理時間がDeadlineを超えた、またはStatus Request自体が期限内に完了しませんでした。

確認方法: 同じOperation IDへ.status()を一回実行し、acceptedrunningretry_scheduledretryAfterSecondsを確認します。Timeout後にOperationが自動Cancelされたとは解釈しません。

修正方法: Workerを監督し、業務SLOに合う正のmaxWaitMillisecondsを呼出単位で指定します。無限待機や固定間隔の独自Pollingへ置き換えません。Timeout後もWorkerは処理を続けられるため、後から同じIDで.status()または新しい有限.wait()を実行できます。

.status().wait()unexpected_responseを返す

症状: Serverへ到達できるのにGenerated Clientがunexpected_responseで停止します。

考えられる原因: HTTP Status、JSON Media Type、Schema Version、Operation ID/Type、State別Field、Outcome Shape、Retry-AfterがCompiled Contractと一致しません。

確認方法: Generated Treeを再生成し、ServerとClientが同じBuildから作られているか確認します。Raw Body、Credential、Thrown ErrorをResultやLogへ追加しないでください。

修正方法: build:compile -> frontend:generate -> frontend:check -> pnpm testを同じReleaseで実行します。Malformed/5xxをClient側で自動Retryせず、Server ContractまたはDeploy不整合を修正します。

Operation ID付き500を調べる

症状: Responseが{"status":"error","code":"internal_error","operationId":"019..."}を返します。

考えられる原因: Operationは受理後にHandlerまたはInfrastructureで予期しないFailureとなりました。Operation ID付きのSafe Errorは、受理前のProtocol Errorとは異なります。

確認方法: IDを変更せず、Human表示、次にJSON表示で確認します。

php blackops operation:inspect 019...
php blackops operation:inspect 019... --json

received -> attempt.started -> attempt.failed -> operation.failedの順と、Application/Framework JSONL Logの同じOperation IDを確認します。HTTPやCLIにException Messageがないのは意図したSafe Surfaceです。Canonical DatabaseのRaw RecordをSupport Ticketへ貼り付けないでください。

修正方法: 同じOperation IDのJournalとSafe LogからFailure Categoryを確認し、Application Handler、Database、Dependencyの原因を修正してから、冪等性を確認した新しいOperationとして再実行します。ThrowableやProtected PayloadをResponseへ追加しません。

Scheduled Operationがconfiguration_errorで停止する

症状: operation:schedule:runがExit 2で停止し、Configuration Errorを返します。

考えられる原因: database:migrateまたはbuild:compileを先に実行していない、Schedule名/Cron/Timezoneが不正、Required Constructor引数を持つValue、または#[Authorize]へApplication-owned ScheduledActorProviderをBindingしていません。

確認方法: SourceとArtifactを更新し、SafeなJSONだけを確認します。

php blackops database:migrate
php blackops build:compile
php blackops operation:schedule:run --json

Credential、Value Payload、Actor情報はErrorへ追加しません。Providerがnullを返す場合は匿名へFallbackせず認可拒否になります。Scheduled OperationのAuthoringとProvider手順を確認してください。

修正方法: Schedule Metadata、Timezone、Value Constructor、Actor Providerを修正してからdatabase:migratebuild:compile、one-shot実行を順に行います。Exit 0の評価結果だけを成功とし、Credentialや未検証ActorをFallbackしません。

Scheduled Occurrenceがacceptedclaimedのまま

症状: operation:schedule:run --jsonacceptedを返したのに、OccurrenceまたはOperationが完了しません。

考えられる原因: Deferred Operationのworker:runが起動していない、Workerが別Database/Schemaを見ている、またはLease/Heartbeatの期限切れからRecovery待ちです。

確認方法: Operation IDを変更せず、Occurrenceの安全な列とJournalの同じOperation IDを照合します。

php blackops worker:run --iterations=1 --idle-sleep-milliseconds=1
php blackops operation:inspect <operation-id> --json

operation:schedule:run --jsonは件数だけを返し、Operation IDを出力しません。上のRead-only Occurrence Queryでoperation_idを得て、<operation-id>へ置き換えます。acceptedはDurable受理であり完了ではありません。Lease Recovery後も同じOperation IDを使い、外部副作用はExactly Onceと解釈しません。

修正方法: Deferred Workerを同じDatabase/Schemaへ接続し、LeaseとHeartbeatの設定を確認してからworker:runを再実行します。Recovery後は同じOperation IDのTerminal Eventを確認し、外部副作用を重複実行しないApplication冪等性を保ちます。

Scheduled Occurrenceがskipped_misfireskipped_overlapになる

症状: JSONのskipped_misfireまたはskipped_overlapが増え、Operation IDがありません。

考えられる原因: Cursorより後から現在のUTC Calendar Minuteまでに一致するSlotが複数あり、最新Slot以外がskipped_misfireになった、または同じScheduleの前回Occurrenceが実行中で最新Slotがskipped_overlapになった状態です。どちらもRunnable Operationを作らない安全なSkipです。

確認方法: schedule_name、UTCのscheduled_atevaluated_atstatecategoryだけを確認します。

Project Rootで、Framework SchemaのRead-only Queryとして実行します。SkeletonのDocker環境ではPostgreSQLへ次のように接続してからSQLを貼り付けます。

docker compose exec -T postgres psql -U blackops -d blackops

別環境ではApplicationのFramework Connection/Schemaへ接続するRead-only PostgreSQL Clientを使い、blackopsはApplication Configurationに合わせて置き換えます。CredentialをCommand例へ直書きしません。正本のQueryはOccurrenceとJournalを安全に確認するにもあります。

SELECT schedule_name, scheduled_at, evaluated_at, state, category
FROM blackops.schedule_occurrences
WHERE schedule_name = 'reports.daily'
ORDER BY scheduled_at DESC
LIMIT 20;

Cron/Timezoneと外部Supervisorの重複起動を見直します。SkipへOperation IDを補って再実行したり、Occurrenceを直接更新したりしません。

修正方法: UTC Cursor、Misfire Window、ScheduleのOverlap設定、外部Supervisorの多重起動を修正し、次の評価Slotをone-shotで確認します。Skip済みOccurrenceを直接Completedへ変更しません。

IDのない500はOperation成立前のBootstrap/Middleware/Protocol境界の失敗です。operation:inspectでは追跡できないため、Credentialを除いたFramework Error Log、Config Validation、Build Artifact、Database Connectionを確認します。

InspectのExit CodeはInvalid ID=2、Unavailable=3、Storage/Decode/Integrity=4です。--jsonのErrorは{"schemaVersion":1,"status":"error","code":"..."}をstderrへ出します。

Local Viewerが起動/表示できない

症状: viewer.disabledviewer.invalid_configurationviewer.runtime_unavailableviewer.bind_failed、またはBrowserで404が返ります。

考えられる原因: Diagnostics Enable Gateが無効、Loopback以外のBind、Port競合、PCNTL未提供、Bootstrap URLの期限切れ、またはHost/Cookie境界が異なります。

確認方法: config/diagnostics.phpenabled127.0.0.1、Port競合、CLI RuntimeのPCNTLを確認します。QuickstartはLocalだけEnabledです。

修正方法: Viewerをphp blackops operation:viewerで明示起動し、その起動で一度だけ出るBootstrap URLへ同じLocal Runtimeからアクセスします。Tokenがない、古いTokenを使う、Session Cookieを捨てる、Host Headerが異なる場合の404はFail-closed動作です。Non-loopback Bindへ変更せず、別のLocal Portへ変える場合はConfigと接続先を同期します。POSTは405で、GET/HEADだけが正常です。

Migration未適用/PostgreSQL接続失敗

症状: HTTP、Worker、Outcome、Retention CommandがTable不在またはPostgreSQL接続Errorで失敗します。

考えられる原因: Migrationを明示適用していない、config/database.phpのHost/Port/Database/UserがProcessごとに異なる、またはPostgreSQLが起動していません。

確認方法: 接続先をSecretなしで確認し、Read-only Statusを実行します。

php blackops database:status --no-interaction
docker compose ps postgres

修正方法: PostgreSQLを起動し、正しいCredentialをEnvironmentから渡してMigrationを適用します。

php blackops database:migrate --dry-run
php blackops database:migrate

HTTP/Worker起動時の暗黙Migrationに頼りません。

StorageKeyProviderが未登録

症状: HTTP、Worker、Console、Scheduled、Outbox、Status/Data Query、またはRotationのRuntime compositionがStorage Protectionを解決できず、安全なConfiguration/Storage Protection Errorで停止します。build:compileStorageKeyProviderの必須Runtime検査を行わないため、Providerが未登録でも成功する場合があります。

考えられる原因: Application Service ProviderでStorageKeyProvider::classのBindingがない、config/app.phpservicesへProviderを登録していない、またはProvider ConstructorがContainerで解決できない状態です。

確認方法: 2. Key ProviderをApplicationへ登録するApplication Commandを照合します。Storage Protectionを解決するRuntime composition(HTTP、Worker、Console等)を実行し、該当SurfaceのSafe Error/Responseだけを確認します。build:compileの成功だけではProvider登録を証明しません。Key Material、Credential、Constructor引数、Throwableを出力せず、build:compileには--json Optionがないことにも注意してください。

修正方法: Application-owned StorageKeyProviderOperationDataReadAuthorizerOperationStatusAuthorizer、必要なTenant ProviderをServiceRegistry::autowire()で登録し、config/app.phpへService Providerを追加してからBuildし、HTTP/Worker/Console等のRuntime compositionを再実行します。該当SurfaceのSource/Testで定義されたSafe Error/Responseを期待し、Keyをset()、Config、Manifest、Artifact、Logへ置かないでください。

Unknown Key/Tag Tamper

症状: 認可済みのJournal/Outcome Read、Worker、またはstorage:protection:rotate --confirmがEnvelope Integrityを検証できず、安全な固定Failureへ縮約します。Rotation ConfirmのStorage/Protection FailureはExit 1、Plan/RotateのInput/Configuration FailureはExit 2です。Journal/Outcome Queryはoperation_journal.protection_failedまたはoperation_outcome.protection_failed等のPublic Safe Codeを返します。storage:protection:planはHeader/Clear MetadataのRead-only集計であり、Unknown Key/Tag Tamperを検出しません。

考えられる原因: BOPD HeaderのKey IDをProviderが解決できない、旧KeyのRead期間が終了している、AADのPurpose/Row/Operation/Tenant Scopeが異なる、またはCiphertext/Tagが改変されています。Malformed Headerも同じRuntime Protection Failureへ縮約されます。

確認方法: 認可済みApplicationのOperationJournalQuery::records()またはOperationOutcomeQuery::find()、Worker処理、Rotation Confirmを実際に実行し、該当Surfaceの固定Safe Code/Exitだけを確認します。Read-onlyの5. DatabaseにRaw Valueがないことを確認するのBOPD Prefix countとoperation:inspectはClear lifecycle列のDiagnosticsであり、Envelope Integrity検査やTamper確認ではありません。FingerprintはRotation Auditの失敗記録だけを照合します。Envelope、Nonce、Tag、Key Material、Payload、Tenant Raw IDをSELECT、Log、Ticketへ出しません。

修正方法: Unknown Keyなら旧Keyを削除せずRead可能なProviderへ一時的に復旧し、同じPurpose/Tenant ScopeでPlan(Read-only)を実行します。Tag TamperやAAD不一致はEnvelopeを手動編集せず、原因を隔離して承認済みBackup/Offline変換の手順へ戻します。RuntimeのPlaintext Fallbackは行いません。

非空の旧Protected SchemaでMigrationが停止

症状: database:migrateが変更前のSafe Migration Errorで停止し、Shellへ非ゼロ終了を返します。正確なTop-level終了値はApplicationのConsole Error境界で確認してください。旧保護対象Tableが非空でも、MigrationはRow内容を検査しません。

考えられる原因: 既存の旧Protected SchemaにRowが残っており、Experimental v1の新しいEnvelope/Tenant契約へ自動変換できないためです。非空判定は安全停止のためだけに使われます。

確認方法: Read-onlyのMigration StatusとTableの空/非空件数だけを確認します。database:migrate --dry-runを使い、Payload、Plaintext、Envelope Header、Key Material、Rowの内容をSELECTしません。database:migrateには--no-interaction Optionはありません。空Tableは0件、非空Tableは停止対象です。

修正方法: 新規ApplicationではDatabaseをReset/RecreateしてからMigrationし、必要なDataはApplicationが承認したFramework外のOffline変換で別途移行します。既存Tableを直接ALTER、暗黙変換、削除して再実行しないでください。完了後にdatabase:migratebuild:compileを順に実行します。

Rotationのremainingが0にならない

症状: Confirm済みRotationはExit Code 0でもremainingが残る、または一部Rowがfailedskippedになります。Protection/Runtime FailureならExit Codeは1、Input/Confirm/Config Errorなら2です。

考えられる原因: Purpose、Tenant Pair、Old Key ID、Checkpointが一致していない、CAS競合でSkipされた、失敗Auditを修復していない、またはDatabase以外のReplica、Backup、Dead Letter、Retention Windowに旧Keyが残っています。

確認方法: 同じScopeでstorage:protection:plan --jsonを再実行し、purpose、Tenant Scope、Key ID、Checkpoint、remainingfailedだけを照合します。Read-only Planは全範囲を集計しますが、Payload、Nonce、Tag、Tenant Raw ID、Key Materialを出しません。失敗FingerprintとCheckpointを安全なAuditから確認します。

修正方法: 旧KeyをRead可能なままにし、同じScope/Checkpointでstorage:protection:rotate --confirm --jsonを再開します。Failed Auditを原因修復後に再処理し、CAS Skipは再Planで残件を確認します。Databaseのremaining=0を確認した後もReplica、Backup、Dead Letter、Retention Windowを別途確認し、すべての境界が完了するまで旧Keyを削除しません。

journal.jsonlへ出力されない

症状: Operationは完了しますが、var/log/journal.jsonlが存在しない、またはRecordが増えません。

考えられる原因: config/journal.phpenabledがfalse、Pathが相対Path、Parent Directoryがない/書込不能、またはbest_effort Observerの失敗を見落としています。

確認方法: ConfigとDirectory権限を確認します。

php -r '$config = require "config/journal.php"; var_export($config["jsonl"] ?? null); echo PHP_EOL;'
test -d var/log && test -w var/log && printf 'journal directory is writable\n'

修正方法: enabled=true、既存の書込可能な絶対Path、best_effortまたはrequiredを設定します。FrameworkはDirectoryを作らないため、Deploy/Setup工程でParent Directoryを準備します。

Local OpenTelemetry Collector/Traceが届かない

症状: Local Collectorは起動するが、Trace/MetricがLogへ現れない、または停止後にReadinessがFailになります。

考えられる原因: Collectorの起動だけではEmitterがSpan/Metricを作成しません。ApplicationのSDK/OTLP Exporterが未登録、collector:4318/v1/traces/v1/metricsが別Network、Flush/Shutdownが未実行、otel-collector-config.yamlのConfig Mountが不正、またはReadinessへCollector接続を誤って含めています。

確認方法: DockerでLocal Collectorを確認するのProvider/MeterProvider/Health Adapter例を照合し、固定DigestのCollector laneをProject Rootで同じTerminalから再実行します。Host laneの$COLLECTOR確認はread前の同じShellで行い、別Shellの未定義変数を使いません。

docker ps --filter 'name=blackops-otel-' --format '{{.Names}}\t{{.Status}}'
docker logs "$(docker ps --filter 'name=blackops-otel-' --format '{{.Names}}' | head -n 1)" | tail -n 20

この固定Digest laneの自動範囲はCollector Ready、Container/Network Isolation、HealthとCleanupです。ApplicationがEmitterを実行した場合だけ、HTTP→Inline、Deferred→Worker→Retry、Outbox Producer→Relay、Metric、JSONL Correlation、MaskをApplicationの実結果として確認します。docker logsだけを成功根拠にせず、Healthの結果も確認してください。Raw Header、Credential、Payload、Outcome、Provider/Exception Detailを貼り付けません。

修正方法: ApplicationとCollectorを同じLocal Networkへ置き、OTLP HTTP Endpointをhttp://collector:4318へ合わせ、Metric用Endpointを分けてFlush/Shutdownします。Invalid traceparentはRaw Headerを保存せずParentなしで処理します。Provider/Exporter FailureはNo-op/Best-effortへ縮退し、Primary OperationとReadinessを変更しません。CollectorをReadiness Checkから外し、Remote BackendやProduction ComposeへLocal設定をコピーしないでください。

Grafana LGTMでTraceまたはMetricが見つからない

症状: Grafanaは起動するが、TempoのTraceまたはPrometheusの blackops.operation.durationまたはblackops_operation_duration_seconds(Histogramの _bucket_sum_count)が表示されません。

考えられる原因: Emitter、Collector、Grafana Datasourceが同じNetwork/Endpointを使っていない、またはProviderのFlush/Shutdown前にApplicationが終了しています。

確認方法: Local Grafana LGTMのReadinessを確認するの自動Readiness laneをProject Rootから起動し、Grafana HTTP Health、固定Digest、loopback Port、失敗時Log、Cleanupを確認します。Trace/Metricの保存確認は、同じページのInteractive laneでApplication-owned Emitterを実行した場合だけ行います。Backend Portを直接公開したり、Grafana APIのResponse全体をLogへ貼ったりしません。

修正方法: Interactive laneでだけ、LGTMのNetwork aliasがcollectorであること、Emitterが同じNetworkでOTLP HTTP 4318へ送っていること、ProviderのFlush/Shutdownが完了していることを確認します。CredentialはShellのGRAFANA_PASSWORD(未指定時local-admin)とContainerのGF_SECURITY_ADMIN_PASSWORDを一致させます。Host laneでは127.0.0.1:<random-otlp-port>、Container laneではhttp://collector:4318を使い分けます。Grafanaの停止をReadinessへ追加せず、Remote CredentialやPersistent VolumeをLocal手順へ持ち込みません。Grafana 3000は閲覧Page、4318はIngestion endpointです。

Outcome Status

OutcomeがPending/Not Found/Expiredか判別できない

症状: OperationOutcomeQuery::find()OperationOutcomeUnavailableになり、処理中、未知のOperation ID、失敗、保持期限切れを区別できません。

考えられる原因: OperationOutcomeQueryはCurrent Actor、Current Tenant、OperationDataPurposeを受けるDefault-deny Queryです。Unknown、Tenant不一致、Deny、Retention削除は同じUnavailableになります。

確認方法: Public OperationStatusQueryGET /operations/{operationId}、またはGenerated .status()で現在Stateを確認します。

修正方法: Public Status Resultを次のように分類します。PHP AdapterでOutcomeだけが必要な場合も、認可済みOperationOutcomeQueryへ明示的なPurposeを渡します。

判定 Applicationが返す状態
Operationが存在し、非Terminal Pending
CompletedかつOutcomeあり Completed
Rejected/Failed/Dead Letter Terminal without outcome
UnknownまたはDeny 404 Unavailable
Allow済みで期限切れを証明 410 Expired

Persistence PayloadやFramework Table Schemaを利用者向けResponseへ直接公開しません。

Sensitive値がJournalで見えない

症状: #[Sensitive]を付けた値が[masked]、除外、Hashとして表示され、入力値を確認できません。

考えられる原因: Sensitive Projectionが意図どおりObserved Journalへの出力を制限しています。これは不具合ではありません。

確認方法: OperationValueのPropertyに付けた#[Sensitive]SensitiveModeを確認します。Raw値をLogへ追加して検証しないでください。

修正方法: Debuggingには非Sensitiveな相関ID、Category、安定したError Codeを使います。Raw Secretが業務処理に不要なら保存しません。秘密値の復元が必要な業務要件は、Applicationの暗号化Store、Key管理、Access Control、監査を別途設計します。

FAQ: 202は完了を意味しますか

いいえ。202 AcceptedはDeferred OperationをDurableに受け付けたことだけを意味します。WorkerのAttempt、Retry、Terminal State、Outcomeを同じOperation IDで追跡してください。

FAQ: 失敗をすべてRejectedへ変換できますか

変換しません。予期された業務拒否だけOperationRejectedExceptionを使います。一時障害はRetryableException、BugやInfrastructure Failureは通常のThrowableとしてSupervision/Failure Policyへ渡します。