Files
summercms/.planning/phases/14-domain-jobs-and-external-integrations/14-06-PLAN.md
2026-10-03 18:56:43 +02:00

29 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, estimate, must_haves
phase plan type wave depends_on files_modified autonomous requirements estimate must_haves
14-domain-jobs-and-external-integrations 06 execute 6
14-05
scripts/check-phase14.sh
modules/fetchguard/client_coverage_test.go
modules/tide/upstream_coverage_test.go
modules/sunscreen/sunscreen_coverage_test.go
modules/beachcomber/typesense/engine_test.go
../fonoteka.go/parity/discogs_truth_tables.php
../fonoteka.go/parity/README.md
../fonoteka.go/plugins/golem15/fonoteka/classes/discogs/testdata/
../fonoteka.go/plugins/golem15/fonoteka/classes/discogs/php_truth_test.go
../fonoteka.go/plugins/golem15/fonoteka/classes/discogs/coverage_test.go
../fonoteka.go/plugins/golem15/fonoteka/phase14_security_test.go
../fonoteka.go/plugins/golem15/fonoteka/phase14_edges_test.go
../fonoteka.go/plugins/golem15/fonoteka/phase14_jobs_test.go
../fonoteka.go/plugins/golem15/fonoteka/write_endpoints_fuzz_test.go
../fonoteka.go/plugins/golem15/fonoteka/testdata/fuzz/FuzzWriteEndpoints/
../fonoteka.go/plugins/golem15/fonoteka/routes_table_phase14_test.go
../fonoteka.go/plugins/golem15/fonoteka/console/phase14_commands_test.go
../fonoteka.go/plugins/golem15/fonoteka/controllers/api/phase14_controllers_test.go
../fonoteka.go/plugins/golem15/fonoteka/classes/phase14_classes_test.go
../fonoteka.go/plugins/golem15/golem/classes/services/coverage_test.go
../fonoteka.go/plugins/golem15/golem/classes/providers/coverage_test.go
../fonoteka.go/plugins/golem15/golem/golem_admin_test.go
../fonoteka.go/plugins/golem15/golem
../fonoteka.go/plugins/golem15/feedback/feedback_edges_test.go
../fonoteka.go/plugins/golem15/feedback/classes/coverage_test.go
../fonoteka.go/plugins/golem15/feedback
.planning/phases/14-domain-jobs-and-external-integrations/14-SECURITY-REVIEW.md
.planning/phases/14-domain-jobs-and-external-integrations/14-VALIDATION.md
.planning/phases/14-domain-jobs-and-external-integrations/COVERAGE.md
.planning/REQUIREMENTS.md
.planning/todos/pending/fetchguard-guarded-http-client.md
.planning/todos/pending/redacting-slog-handler.md
.planning/todos/done/fetchguard-guarded-http-client.md
.planning/todos/done/redacting-slog-handler.md
true
JOBS-02
JOBS-03
SRCH-02
INTG-01
INTG-02
API-08
CLI-05
tokens raw_tokens tasks confidence
380000 380000 4 low
truths artifacts key_links prohibitions
`scripts/check-phase14.sh` (summercms.go) is fail-closed with `--self-test`, `--go`, `--parity`, `--named`, `--removal`, `--coverage`, `--evidence` and `--all`; `--all` (every stage except `--removal`) runs vet and tests in summercms.go and in fonoteka.go including both new submodule plugins with -race, the parity corpus at exactly 175 recorded, 172 ported and passing, 3 pending (the D-09 routes), every TestFonotekaNuxtFlows subtest, TestUpstreamSidecarsAreReplayed, check_corpus `--require-recorded --check-secrets`, TestDocsTree and docs:build --check; `--self-test` proves each detector fails on planted input.
PHP truth tables generated by `parity/discogs_truth_tables.php` (running the PHP DiscogsMapper, DiscogsInputParser, ReleaseMatchScorer and PriceSuggestionResolver directly, as csv_truth_tables.php does) are committed under classes/discogs/testdata/php_*.json and `TestPHPTruthDiscogs` reproduces every row byte for byte, including price rounding.
Every Go package created or changed in Phase 14 reaches at least 80% statement coverage: summercms.go fetchguard, tide, sunscreen, beachcomber and beachcomber/typesense; fonoteka classes/discogs and console; every Phase 14 function in the fonoteka root, classes and controllers/api packages at 80% by `go tool cover -func`; every package of sm-golem-plugin and sm-feedback-plugin; the numbers are recorded in 14-VALIDATION.md.
`TestRouteTablePhase14` pins all eleven Phase 14 fonoteka routes and the four feedback routes (group, method, constraints, scope, throttles and buckets), and `FuzzWriteEndpoints` covers the Phase 14 write routes (apply-release, import/discogs, recognize, cover-price, credential tests, feedback submit and me/hidden) asserting no column outside each allow-list changes and no 500 PHP does not answer.
Each mitigated T-14 threat of plans 14-01 to 14-05 has a named test in `TestPhase14Threats` (or the named module test) that fails when its protection is removed; `check-phase14.sh --removal` applies anchor-exact mutations, requires the named test to fail on an assertion and restores each file byte for byte (cmp); 14-SECURITY-REVIEW.md maps every T-14 id to category, severity, disposition, protecting file and that test.
Every edge truth of plans 14-02 to 14-05 is pinned one step either side in `TestPhase14Edges` and the feedback edge tests (limiter threshold and budget, Retry-After parsing, MAX_CANDIDATES, prune cutoff, inbound limits 60/20/10/12, feedback validation limits), and each prohibition of plans 14-01 to 14-05 has a negative test the gate requires by name.
Per D-06, D-07, D-13 and D-14, `--evidence` refuses a REQUIREMENTS.md that still carries the SDK wording for INTG-02 or sitemap for API-08, and a ROADMAP Phase 14 section without the album Discogs and recognize routes or the sm-golem-plugin and sm-feedback-plugin repos; REQUIREMENTS.md marks JOBS-02, JOBS-03, SRCH-02, INTG-01, INTG-02, API-08 and CLI-05 Complete; 14-VALIDATION.md has real task ids, no pending row, `nyquist_compliant: true` and `wave_0_complete: true`; the two folded todos move to `.planning/todos/done/`.
COVERAGE.md lists every Discogs, Anthropic, OpenAI-compatible and G15Office capability the PHP reference uses as INTEGRATE with a named test, and every other capability as OPT-OUT with a reason; `--evidence` refuses an INTEGRATE row without a passing named test.
PriceSuggestionResolver results equal PHP's for every truth-table input (every currency, empty suggestions, rounding ties), pinned by TestPHPTruthDiscogs.
path provides contains
scripts/check-phase14.sh fail-closed Phase 14 gate EXPECTED_PORTED=172
path provides contains
../fonoteka.go/parity/discogs_truth_tables.php PHP truth-table generator for the Discogs pure classes PriceSuggestionResolver
path provides contains
../fonoteka.go/plugins/golem15/fonoteka/phase14_security_test.go TestPhase14Threats TestPhase14Threats
path provides
.planning/phases/14-domain-jobs-and-external-integrations/14-SECURITY-REVIEW.md threat-to-test evidence
from to via pattern
scripts/check-phase14.sh .planning/phases/14-domain-jobs-and-external-integrations/14-VALIDATION.md --named reads every test the validation map names; --evidence refuses pending or TBD rows 14-VALIDATION.md
from to via pattern
../fonoteka.go/plugins/golem15/fonoteka/classes/discogs/php_truth_test.go ../fonoteka.go/parity/discogs_truth_tables.php testdata/php_*.json written by the PHP generator php_
requirement_id category statement status verification
INTG-01 transparency Pending routes MUST NOT be counted as passing; the three D-09 routes stay pending and the gate fails if any pending count differs from 3 resolved test
requirement_id category statement status verification
INTG-02 transparency A threat MUST NOT be marked mitigated in 14-SECURITY-REVIEW.md without a named test that was run and seen to fail when its protection is removed resolved test

Phase Goal

ROADMAP Phase 14 goal (verbatim, not in user-story form): The domain-specific River jobs (CSV import write, Discogs match, wishlist digest), the reindex command, the Discogs client and AI cover recognition are ported on top of the Phase 11 jobs/realtime/search infrastructure and the Phase 13 API surface they serve.

This plan's slice: the phase is proven. Every Phase 14 package has full unit coverage, the PHP truth tables pin the Discogs rules, each threat has a test that fails without its protection, and one gate script says green or red for the whole phase (lean-mode rule 3: unit tests are the last plan).

Write the PHP truth-table generator and tests, bring every Phase 14 package to at least 80% coverage with edge and threat tests, extend the route-table and fuzz tests, build `scripts/check-phase14.sh`, and record the security review, validation evidence, requirement status and API coverage.

Purpose: CLAUDE.md lean-mode rule 3; the gate is what /gsd-verify-work 14 runs. Decisions verified: every D-01 to D-21 that produced code, plus the D-06/D-07/D-13/D-14 rewording. Output: tests in all four repositories, the gate script, 14-SECURITY-REVIEW.md, a validated 14-VALIDATION.md, COVERAGE.md checks, REQUIREMENTS statuses.

Repos: summercms.go (gate, framework tests, planning docs in a separate commit), fonoteka.go, sm-golem-plugin and sm-feedback-plugin (tests committed and pushed in each checkout, then one pointer-bump commit per plugin in fonoteka.go). Never add co-author tags.

<execution_context> @/.claude/gsd-core/workflows/execute-plan.md @/.claude/gsd-core/templates/summary.md </execution_context>

@.planning/phases/14-domain-jobs-and-external-integrations/14-VALIDATION.md @.planning/phases/14-domain-jobs-and-external-integrations/COVERAGE.md @.planning/phases/14-domain-jobs-and-external-integrations/14-01-SUMMARY.md @.planning/phases/14-domain-jobs-and-external-integrations/14-02-SUMMARY.md @.planning/phases/14-domain-jobs-and-external-integrations/14-03-SUMMARY.md @.planning/phases/14-domain-jobs-and-external-integrations/14-04-SUMMARY.md @.planning/phases/14-domain-jobs-and-external-integrations/14-05-SUMMARY.md @scripts/check-phase13.sh - check-phase13.sh structure: env overrides (`PHASE13_ROOT`, `PHASE13_APP`, `PHASE13_PHASE_DIR`), `APP_PLUGINS`, `EXPECTED_PORTED`, `EXPECTED_PENDING`, `COVERAGE_FLOOR=80`, the python `go test -json` detector (exit 1 fail, 2 skip, 3 zero tests, 4 non-JSON, 5 required test missing, 6 race), `expect_detect`, `run_go`, `corpus_scan`, `manifest_count`, `run_parity`, `run_named`, `coverage_report`, `func_floor`, `removal_table`, `removal_harness` (refuses dirty files, cmp restore), `evidence_check`, `run_self_test`. - 13-06 precedents: `FuzzWriteEndpoints` with its committed seed corpus under testdata/fuzz, `TestPhase13Threats`, route-table tests over `surf.BuildRouter(...).Routes()`. - parity/csv_truth_tables.php (PHP_ROOT env, require_once the classes, stub ApplicationException, write_table with JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRESERVE_ZERO_FRACTION). - Threat ids T-14-01 to T-14-36 and T-14-SC from the five earlier plans' threat models.

Artifacts this phase produces

(This plan's share.)

  • scripts/check-phase14.sh (--self-test --go --parity --named --removal --coverage --evidence --all; PHASE14_ROOT, PHASE14_APP, PHASE14_PHASE_DIR; EXPECTED_ROUTES=175, EXPECTED_PORTED=172, EXPECTED_PENDING=3, COVERAGE_FLOOR=80).
  • parity/discogs_truth_tables.php; classes/discogs/testdata/php_mapper.json, php_input_parser.json, php_scorer.json, php_price_suggestion.json.
  • Tests: TestPHPTruthDiscogs, TestPhase14Threats, TestPhase14Edges, TestPhase14Jobs, TestRouteTablePhase14 (complete), FuzzWriteEndpoints (Phase 14 routes), coverage tests per package, TestFeedbackEdges, TestGolemAdminSchemas.
  • Evidence: 14-SECURITY-REVIEW.md, validated 14-VALIDATION.md, REQUIREMENTS statuses, todos moved to done.

Assumptions

  • The gate lives in summercms.go/scripts and runs application commands in the sibling ../fonoteka.go, as check-phase13.sh does; the two plugin submodules are tested through the application workspace.
  • Live vendor calls are never part of the gate (D-15); the manual-only rows of 14-VALIDATION.md stay manual.
Task 1: One command proves the whole phase green or red: check-phase14.sh runs both repositories, the corpus and the named tests scripts/check-phase14.sh scripts/check-phase13.sh (whole file), .planning/phases/14-domain-jobs-and-external-integrations/14-VALIDATION.md, ../fonoteka.go/parity/parity_test.go (expectedPHPRoutes, expectedPortedRoutes), ../fonoteka.go/parity/check_corpus.go Copy check-phase13.sh's structure into scripts/check-phase14.sh with `PHASE14_*` overrides, `PHASE_DIR` pointing at the Phase 14 directory, `APP_PLUGINS=(./plugins/golem15/fonoteka/... ./plugins/golem15/user/... ./plugins/golem15/golem/... ./plugins/golem15/feedback/...)`, `EXPECTED_ROUTES=175`, `EXPECTED_PORTED=172`, `EXPECTED_PENDING=3`, `COVERAGE_FLOOR=80`, and the python detector renamed `phase14_detect` with the same exit codes. Wire `--go` (vet and `go test ./... -count=1` in summercms.go; vet and `go test ./... -count=1 -race` over APP_PLUGINS plus `./app/... ./parity/...` in fonoteka.go), `--parity` (TestParityCorpus with the three counts read from its output and from the manifest, every TestFonotekaNuxtFlows subtest, TestBroadcastGoldens, TestUpstreamSidecarsAreReplayed, check_corpus `--require-recorded --check-secrets`, TestDocsTree, docs:build --check) and `--self-test` (each detector fails on a planted failing, skipped, zero-test, racy and non-JSON input, and a planted pending count of 4 fails `--parity`). Tasks 3 and 4 add the `--named`, `--removal`, `--coverage` and `--evidence` stages to this script; `--all` runs every stage the script defines except `--removal`, which edits tracked source and runs on its own (the Phase 13 precedent). An unknown flag prints usage and exits 2. bash -n scripts/check-phase14.sh && bash scripts/check-phase14.sh --self-test && bash scripts/check-phase14.sh --go && bash scripts/check-phase14.sh --parity Non-zero exit from any stage; the self-test reports a detector that did not fail on its planted input; --parity reports counts other than 175 recorded, 172 ported and passing, 3 pending, or any failing flow, sidecar, secret or docs check. - `grep -c 'EXPECTED_PORTED=172' scripts/check-phase14.sh` and `grep -c 'EXPECTED_PENDING=3' scripts/check-phase14.sh` each print 1. - `grep -c 'plugins/golem15/golem/\.\.\.' scripts/check-phase14.sh` and `grep -c 'plugins/golem15/feedback/\.\.\.' scripts/check-phase14.sh` each print at least 1. - `bash scripts/check-phase14.sh --bogus` exits 2 and prints the usage text. The gate runs end to end over both repositories and the corpus with exact counts, and fails closed. Task 2: The Discogs rules match PHP row for row, and every Phase 14 application package is fully covered at its edges ../fonoteka.go/parity/discogs_truth_tables.php, ../fonoteka.go/parity/README.md, ../fonoteka.go/plugins/golem15/fonoteka/classes/discogs/testdata/, ../fonoteka.go/plugins/golem15/fonoteka/classes/discogs/php_truth_test.go, ../fonoteka.go/plugins/golem15/fonoteka/classes/discogs/coverage_test.go, ../fonoteka.go/plugins/golem15/fonoteka/phase14_edges_test.go, ../fonoteka.go/plugins/golem15/fonoteka/phase14_jobs_test.go, ../fonoteka.go/plugins/golem15/fonoteka/write_endpoints_fuzz_test.go, ../fonoteka.go/plugins/golem15/fonoteka/testdata/fuzz/FuzzWriteEndpoints/, ../fonoteka.go/plugins/golem15/fonoteka/routes_table_phase14_test.go, ../fonoteka.go/plugins/golem15/fonoteka/console/phase14_commands_test.go, ../fonoteka.go/plugins/golem15/fonoteka/controllers/api/phase14_controllers_test.go, ../fonoteka.go/plugins/golem15/fonoteka/classes/phase14_classes_test.go ../fonoteka.go/parity/csv_truth_tables.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/classes/discogs/{DiscogsMapper,DiscogsInputParser,ReleaseMatchScorer,PriceSuggestionResolver}.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/fonoteka/tests/unit/{DiscogsMapperTest,DiscogsInputParserTest,ReleaseMatchScorerTest,PriceSuggestionResolverTest,DiscogsCandidateMapperTest}.php, ../fonoteka.go/plugins/golem15/fonoteka/write_endpoints_fuzz_test.go, ../fonoteka.go/plugins/golem15/fonoteka/routes_table_phase14_test.go, ../fonoteka.go/plugins/golem15/fonoteka/classes/discogs/*.go, the 14-02 to 14-05 SUMMARY files (edge truths and test names) Per lean-mode rule 3 and the edge truths of plans 14-02 to 14-05.

(1) parity/discogs_truth_tables.php follows csv_truth_tables.php: PHP_ROOT from the environment, require_once the four classes, stub what they need, and write php_mapper.json (mapRelease, mapSearchResult, mapMasterVersion over the PHP unit-test fixtures plus edge releases: missing images, multiple formats, unicode artists, master releases), php_input_parser.json (URLs, ids, barcodes with and without check digits, garbage), php_scorer.json and php_price_suggestion.json (every currency, empty suggestions, rounding ties) into classes/discogs/testdata. php_truth_test.go TestPHPTruthDiscogs replays every row and compares JSON bytes. README documents the regeneration command.

(2) Coverage to at least 80%: classes/discogs (coverage_test.go for client error branches, limiter store errors, applicator and cover fetcher branches), console (phase14_commands_test.go), and every Phase 14 function in the root (workers, wiring), classes (album_recognition, CSV write-service variants, WR-02 paths) and controllers/api (match, apply, import, cover-price, credential tests, recognize) packages by go tool cover -func.

(3) phase14_edges_test.go TestPhase14Edges: limiter 50/51 and budget 15/16 s, Retry-After absent/non-numeric/numeric, MAX_CANDIDATES 10/11, prune cutoff at exactly 90 days and one second older, inbound limits 60/61, 20/21, 10/11 and the token cover-price throttle 12/13; phase14_jobs_test.go TestPhase14Jobs (cancel during a paused match, resume after re-dispatch writes the same rows, import of an already written row is skipped). routes_table_phase14_test.go completes TestRouteTablePhase14 for the eleven fonoteka routes. write_endpoints_fuzz_test.go adds the Phase 14 write routes to FuzzWriteEndpoints with a committed seed corpus. go -C ../fonoteka.go vet ./... && go -C ../fonoteka.go test ./plugins/golem15/fonoteka ./plugins/golem15/fonoteka/classes/discogs -count=1 -race -v -run '^(TestPHPTruthDiscogs|TestPhase14Edges|TestPhase14Jobs|TestRouteTablePhase14|FuzzWriteEndpoints)$' && go -C ../fonoteka.go test ./plugins/golem15/fonoteka/... -count=1 -cover <fails_when>Any command exits non-zero; a verbose run prints "--- FAIL", "no tests to run", "--- SKIP" or "DATA RACE", or lacks "--- PASS" for TestPHPTruthDiscogs, TestPhase14Edges, TestPhase14Jobs, TestRouteTablePhase14 and FuzzWriteEndpoints; the cover run reports below 80.0% for classes/discogs or console.</fails_when> <acceptance_criteria> - ls ../fonoteka.go/plugins/golem15/fonoteka/classes/discogs/testdata/php_mapper.json ../fonoteka.go/plugins/golem15/fonoteka/classes/discogs/testdata/php_price_suggestion.json succeeds. - grep -c 'PriceSuggestionResolver' ../fonoteka.go/parity/discogs_truth_tables.php prints at least 1. - ls ../fonoteka.go/plugins/golem15/fonoteka/testdata/fuzz/FuzzWriteEndpoints/ | wc -l is larger than before this task. </acceptance_criteria> The Discogs rules are pinned to PHP's own output and the application side of the phase is covered at its edges.

Task 3: Each Phase 14 threat has a test that fails without its protection, and the framework and both new plugins are fully covered modules/fetchguard/client_coverage_test.go, modules/tide/upstream_coverage_test.go, modules/sunscreen/sunscreen_coverage_test.go, modules/beachcomber/typesense/engine_test.go, ../fonoteka.go/plugins/golem15/fonoteka/phase14_security_test.go, ../fonoteka.go/plugins/golem15/golem/classes/services/coverage_test.go, ../fonoteka.go/plugins/golem15/golem/classes/providers/coverage_test.go, ../fonoteka.go/plugins/golem15/golem/golem_admin_test.go, ../fonoteka.go/plugins/golem15/golem, ../fonoteka.go/plugins/golem15/feedback/feedback_edges_test.go, ../fonoteka.go/plugins/golem15/feedback/classes/coverage_test.go, ../fonoteka.go/plugins/golem15/feedback, scripts/check-phase14.sh, .planning/phases/14-domain-jobs-and-external-integrations/14-SECURITY-REVIEW.md scripts/check-phase13.sh (removal_table, removal_harness, run_named, coverage_report, func_floor), .planning/phases/13-p-ytarium-api-wishlist-notifications-csv-credentials-public/13-SECURITY-REVIEW.md (format), the threat_model blocks of 14-01-PLAN.md to 14-05-PLAN.md, ../fonoteka.go/plugins/golem15/fonoteka/phase13_security_test.go, modules/fetchguard/client.go, modules/tide/upstream.go, modules/tide/upstream_proxy.go, modules/sunscreen/sunscreen.go Per security enforcement (ASVS level 1, block on high).

(1) Coverage at 80% or more for modules/fetchguard, modules/tide, modules/sunscreen, modules/beachcomber and modules/beachcomber/typesense (new *_coverage_test.go files for remaining branches: transport errors, cap edges, proxy forward-mode refusal paths, CA reuse errors, redaction of LogValuer groups), and for every package of sm-golem-plugin (services, providers, security, factories, valueobjects, models, console, controllers; TestGolemAdminSchemas compiles the admin YAML under cabana) and sm-feedback-plugin (classes, controllers/api, models, console; TestFeedbackEdges pins each validation limit one step either side). Plugin tests are committed and pushed in each checkout, then each pointer is bumped in fonoteka.go in its own commit.

(2) phase14_security_test.go TestPhase14Threats: one subtest per mitigated application threat (T-14-08 to T-14-36) that drives the real handler or worker and asserts the protection; framework threats (T-14-01 to T-14-07) map to their named module tests. check-phase14.sh --named requires every test named in 14-VALIDATION.md and the security review by exact name; --removal gets a removal_table row per mitigated threat (anchor-exact mutation of the protecting line, the named test that must fail on an assertion, cmp restore; refuses files with uncommitted changes); --coverage enforces the package floors and the per-function floors (go tool cover -func) for the root, classes and controllers/api Phase 14 functions.

(3) 14-SECURITY-REVIEW.md maps every T-14 id (including T-14-SC and the accepted T-14-28) to category, severity, disposition, protecting file and the named test seen failing under --removal, with the canon referrals of plans 14-02 to 14-05 listed as covered by this review. go vet ./... && go test ./modules/fetchguard ./modules/tide ./modules/sunscreen ./modules/beachcomber/... -count=1 -race -cover && go -C ../fonoteka.go test ./plugins/golem15/fonoteka -count=1 -race -v -run '^(TestPhase14Threats)$' && go -C ../fonoteka.go test ./plugins/golem15/golem/... ./plugins/golem15/feedback/... -count=1 -race -cover && bash scripts/check-phase14.sh --named && bash scripts/check-phase14.sh --coverage && bash scripts/check-phase14.sh --removal <fails_when>Any command exits non-zero; a cover line below 80.0% for a listed package; the verbose run prints "--- FAIL", "no tests to run", "--- SKIP" or "DATA RACE", or lacks "--- PASS: TestPhase14Threats"; --removal reports a mutation whose named test still passes or a file that does not restore byte for byte.</fails_when> <acceptance_criteria> - grep -c 'T-14-' .planning/phases/14-domain-jobs-and-external-integrations/14-SECURITY-REVIEW.md prints at least 37. - grep -cE '^run_(named|removal|coverage)\(\)' scripts/check-phase14.sh prints 3. - git -C ../fonoteka.go/plugins/golem15/golem status --porcelain --branch and the same for feedback show no "ahead". </acceptance_criteria> Framework, golem and feedback code are fully covered and every threat is proven by a test that fails without its protection.

Task 4: The phase record is complete: validation signed off, requirements marked, API coverage checked, folded todos closed, and the whole gate green scripts/check-phase14.sh, .planning/phases/14-domain-jobs-and-external-integrations/14-VALIDATION.md, .planning/phases/14-domain-jobs-and-external-integrations/COVERAGE.md, .planning/REQUIREMENTS.md, .planning/todos/pending/fetchguard-guarded-http-client.md, .planning/todos/pending/redacting-slog-handler.md, .planning/todos/done/fetchguard-guarded-http-client.md, .planning/todos/done/redacting-slog-handler.md .planning/phases/14-domain-jobs-and-external-integrations/14-VALIDATION.md, .planning/phases/14-domain-jobs-and-external-integrations/COVERAGE.md, .planning/REQUIREMENTS.md, .planning/ROADMAP.md (Phase 14 section), scripts/check-phase13.sh (evidence_check), the 14-01 to 14-05 SUMMARY files Per D-06, D-07, D-13, D-14 and the API coverage contract.

(1) --evidence in check-phase14.sh refuses: REQUIREMENTS.md still containing the SDK wording for INTG-02 or "sitemap output" in API-08; a ROADMAP Phase 14 **Repos:** line plus success-criteria block (the lines between **Success Criteria** and **Plans:**, not the plan list) missing albums/import/discogs, recognize, sm-golem-plugin or sm-feedback-plugin; any 14-VALIDATION.md row that is pending, TBD or names a test that did not pass in this run; frontmatter without nyquist_compliant: true and wave_0_complete: true; a COVERAGE.md INTEGRATE row whose named test is missing or did not pass, or an OPT-OUT row without a reason; a security review row without a test. --all runs every stage except --removal.

(2) Planning docs (one commit in summercms.go, planning files only, Edit not Write for existing files): 14-VALIDATION.md gets real task ids (14-01-T1 … 14-06-T4) in its Per-Task Verification Map, the measured coverage numbers, status green per row, status: validated, nyquist_compliant: true, wave_0_complete: true; REQUIREMENTS.md marks JOBS-02, JOBS-03, SRCH-02, INTG-01, INTG-02, API-08 and CLI-05 Complete in both the checklist and the traceability table; COVERAGE.md gets the named test per INTEGRATE row; git mv the two folded todos from pending to done.

(3) Run bash scripts/check-phase14.sh --all and record its final summary line in 14-VALIDATION.md. bash scripts/check-phase14.sh --evidence && bash scripts/check-phase14.sh --all && grep -q 'nyquist_compliant: true' .planning/phases/14-domain-jobs-and-external-integrations/14-VALIDATION.md && test -f .planning/todos/done/fetchguard-guarded-http-client.md && test -f .planning/todos/done/redacting-slog-handler.md <fails_when>Non-zero exit from --evidence or --all; the validation file lacks nyquist_compliant: true; either folded todo is not in .planning/todos/done.</fails_when> <acceptance_criteria> - grep -cE '^\| (JOBS-02|JOBS-03|SRCH-02|INTG-01|INTG-02|API-08|CLI-05) \| Phase 14 \| Complete' .planning/REQUIREMENTS.md prints 7. - grep -cE '^run_evidence\(\)' scripts/check-phase14.sh prints 1 and the --all branch calls run_evidence. - grep -cE '^\|.*\| ⬜ pending \|$' .planning/phases/14-domain-jobs-and-external-integrations/14-VALIDATION.md prints 0. - ls .planning/todos/pending/ | grep -cE 'fetchguard-guarded-http-client|redacting-slog-handler' prints 0. </acceptance_criteria> Phase 14 has a green gate, a signed-off validation map, complete requirements and a decided API coverage matrix.

<threat_model>

Trust Boundaries

Boundary Description
Gate script → tracked source The removal harness edits and restores tracked files
Gate verdict → phase sign-off A false green would close the phase with gaps

STRIDE Threat Register

Threat ID Category Component Severity Disposition Mitigation Plan
T-14-37 Repudiation gate counts medium mitigate Exact 175/172/3 counts from test output and manifest, zero-test and skip detectors, planted-input self-test (Task 1).
T-14-38 Tampering --removal harness medium mitigate Refuses files with uncommitted changes, anchor-exact edits, cmp restore after each mutation, and runs only on its own flag, never inside --all (Tasks 1 and 3).
T-14-SC Tampering package installs low accept No package installs; PHP truth tables run the existing PHP checkout.
</threat_model>
- `bash scripts/check-phase14.sh --all` green in summercms.go. - Both plugin submodules pushed with no local commits ahead; fonoteka.go pointers committed.

<success_criteria>

  • Full unit coverage of all Phase 14 code; PHP truth tables for the Discogs pure classes.
  • Every T-14 threat proven by a failing-without-protection test; gate, validation, requirements and API coverage evidence complete. </success_criteria>
Create `.planning/phases/14-domain-jobs-and-external-integrations/14-06-SUMMARY.md` when done.