Skip to content

P0: Redesign the PHP SDK documentation using One Identity #315

Closed

Description

@rmcdaniel

Priority: P0, explicitly requested for the redesign. Accountable repository agent: sdk-php. General coordinates the shared identity and cross-repository delivery.

The current product presents different identities across its sites. Implement the supplied redesign so users retain one product identity while moving between the main documentation, Python, Rust, PHP, Cloud and status surfaces.

Design authority

  • One Identity redesign.
  • Supplied eight-page Durable Workflow — One Identity PDF, SHA256 5a71d08636a1e2714e8dd4b6561ce0a619453c842de4de647cc3e345f7706e50.
  • This repository's exact reference: Php.dc.html, SHA256 e36bbcd43f7ef00568a9f9f86f6e3466d4f99cc445ddd8efaf6d339c7031d205. The verified original export and shared identity export are being handed to the assigned agent through the existing private artifact channel; do not put private storage/workspace details into public source.

Scope and acceptance

Repository acceptance:

  • Implement the reference PHP hero, readable install/worker/client code panel and primary Laravel path, with the plain-PHP secondary path.
  • Implement the three Laravel / Plain PHP / Symfony entry cards and the two Self-hosted Server / Managed Cloud runtime cards, linking to the existing complete guides and supported transition matrix.
  • Preserve the existing Laravel audience's embedded/service choices, DI/configuration/logging/testing guidance, real published version/install constraint, compatibility and historical documentation. The3.10 source preparation and combined-minor release gates remain separate; this redesign must not imply that an unpublished release or future service support floor is available.
  • Preserve the real portal's API/reference and release-channel behavior while extending the shared design through docs/guide/reference chrome.

Implement the supplied One Durable Workflow redesign faithfully in this repository's existing site components. The exported HTML is a visual specification; its support.js and bundled React runtime are reference-viewer files, not production dependencies.

Shared acceptance:

  • Use the unchanged canonical flowchart SVG, original colors/proportions, and Durable Workflow / <surface> lockup. Surface names are lowercase JetBrains Mono in Durable Green; dark mode uses Mint and the logo's Paper chip (8px radius, 4px padding). Remove the competing DW/generic marks.
  • Apply the same light-default, dark-opt-in palette, Space Grotesk600 headings, Inter400/500/600 text and JetBrains Mono code/labels. Keep code blocks Ink in both themes, 6px/44px actions, 8px bordered cards, the reference spacing/hierarchy, and status-only amber/red/blue.
  • Use the common Docs / SDKs / Cloud / Pricing / Status navigation, keyboard-accessible Python/Rust/PHP SDK switcher, current-surface treatment and contextual CTA. Keep the four-column Brand / SDKs / Run / Project footer. Its linked status pill must reflect accepted current status or an honest unknown/stale state; the mock's static green text is not health evidence.
  • Keep working URLs, page anchors, search, API/reference navigation, compatibility and legal links. Make the layout work at desktop, tablet and narrow mobile widths, with keyboard/focus/contrast, semantic landmarks and working copy controls; code scrolling stays inside its block.
  • Use actual published package/support facts and real service data. The mock's versions, example output, dates, prices and health percentages are not new release, support, billing or availability authority.
  • Return an ordinary draft PR, current-head required checks, built-page screenshots in both themes at representative desktop/mobile widths, functional link/copy/navigation checks, and the actual deployment/live verification through the repository's existing protected flow. Preserve current operating, publication and credential boundaries.

Shared identity lead and canonical token/asset acceptance: durable-workflow/durable-workflow.github.io#483. Match that issue and the supplied identity artboard; report concrete inconsistencies without blocking independent source work.

Activity

  1. added
    priority:P0Immediate release or data-integrity risk
    agent:sdk-phpWork done by the sdk-php repo agent
    on Nov 5, 2026
  2. rmcdaniel commented on Nov 5, 2026

    @rmcdaniel
    MemberAuthor

    I own this P0 and have preserved lower-priority #314 at its pushed draft checkpoint (record). Implementation is isolated from accepted main 3716c192.

    Verified the exact PDF, PHP artboard, shared identity artboard and unchanged canonical SVG hashes against this issue. The first source slice implements their shared palette/type/logo/navigation/footer in the existing Eleventy and phpDocumentor templates, then the three PHP entry cards and two runtime ownership panels. Current guide routes, release-owned install metadata and compatibility remain authoritative. The static footer will say status unknown with a link until an accepted fresh status source exists.

    The stable publisher currently selects a complete published SDK checkout (with a same-product-code documentation override); main is unreleased 3.10 source preparation. I will return the narrow presentation-source/published-package-source split and both immutable revisions for review before deployment, preserving actual published API/examples/contracts and all combined-minor gates. Source screenshots/functional checks and ordinary fresh required checks precede publication acceptance. No release or future support floor is selected by this redesign.

  3. rmcdaniel commented on Nov 5, 2026

    @rmcdaniel
    MemberAuthor

    The first UI slice is draft #316. Actual local source qualification now includes the portal plus 386 generated API pages, 56 browser surface/theme/viewport cells on existing Chrome, keyboard SDK switching, exact code copying, light-default/dark-opt-in controls and zero horizontal overflow. The initial font-README page and browser/layout findings were fixed normally; initial failed CI remains historical until the successor completes fresh checks.

    The proposed stable-publisher graph stays in this draft: stable_tag / optional unchanged-product stable_source select SDK/API/examples/contracts; an exact accepted-main presentation_source selects only the landing page, layout, identity components and assets into an isolated staging directory. Published guide bodies and generated API index stay on the selected source. The release-data adapter reads the published checkout, not presentation metadata. Seven offline history/binding controls plus 19 existing channel controls pass. The final artifact records selected source, published tag commit, presentation commit and exact workflow revision, and refuses altered staging inputs.

    No deployment input tuple is selected yet. The concrete eventual source is published SDK 3.9.4 (11085f0c624674a4b70d3a6fb3e83eaff3869fcb), existing stable docs source 6a821568db5c72983bd3990fe27c7990f092db12 and the future accepted presentation/main commit. Required current-head checks, stable rendered comparison and publication-path acceptance still precede dispatch. The workflow still uses the existing setup-php path, so its affected publication boundary remains to reconcile with the accepted central fix; this draft adds no per-repository installer or guard. No 3.10 package/API/support-floor promotion, native/installed execution or release follows.

  4. rmcdaniel commented on Nov 5, 2026

    @rmcdaniel
    MemberAuthor

    #316 is normally merged at a4315bcdf62b4a8466c25bd007a9a9d6b06d1f45, with the reviewed tree and unchanged product/API source, examples, manifest and runtime configuration. Actual-main acceptance records 42 terminal checks (40 success + two intended skips), the passing preview build, exact screenshot artifact and safe branch cleanup. Source screenshots cover representative desktop/mobile pages in both themes; the shared status consumer is the final canonical f8198fa2 source.

    The one stable build-only run selected published 3.9.4, SDK/docs source 6a821568db5c72983bd3990fe27c7990f092db12, presentation a4315bcd and build_only=true. It is NONPASS, with deployment skipped. All 393 rendered pages, 17 guide destinations and published contract-derived commands/examples passed. The subsequent analytics/style checker incorrectly compared new presentation CSS with the old SDK template. #317 is the isolated correction, retaining exact asset equality and SDK-owned analytics. Its five focused regression groups pass locally; the original checker fails three. The same corrected checker passes the actual stable render (17 portal + 376 API pages). Hosted qualification is running normally.

    I own #317, the corrected stable candidate and eventual protected deployment/live acceptance. The actual publisher's networked setup-php/APT boundary remains held on central #297 qualification/adoption, owned by CLI/General; no local installer or guard is being added. Its concrete caller remains Ubuntu 24.04/x64, PHP 8.3, Composer 2.10.3, coverage none, plus the current Chromium dependency-install path. Source checks do not qualify that publishing path. Live still selects the previous 6a821568 documentation; this issue remains open until actual delivery and live verification. No 3.10 tag, early support floor, installed/native/authentication or release result follows.

  5. rmcdaniel commented on Nov 5, 2026

    @rmcdaniel
    MemberAuthor

    #317 is accepted on actual main 260af3c8 with 42 terminal main checks (40 success + two intended skips), matching reviewed tree/parents, unchanged product source, safe branch cleanup and a successful portal build with deployment skipped. Acceptance receipt. Live audit remains 6a821568 with the prior SHA256.

    The corrected stable build-only run is retained as NONPASS, deployment skipped. It passed rendering, contract/link checks and analytics, then exposed the API's older header in Chromium. phpDocumentor implicitly selects .phpdoc/template from its working directory, ahead of the explicit template argument. #319 fixes the staged directory/renderer working directory and adds the actual stable-source/accepted-presentation composition to normal CI, preserving its existing legacy checks.

    Current #319 source passes seven isolation controls, 393 page/link/contract checks, analytics across 17 portal + 376 API pages and 56 local browser cells with 12 desktop/mobile light/dark screenshots. The old render reproduces the missing-header refusal. All 376 API page paths, normalized content text, content anchor IDs and links are identical before/after the layout correction; the SDK checkout remains clean at 6a821568. Published 3.9 onboarding stays in the screenshots. These are source/UI results; fresh current-head hosted checks remain in progress.

    I own #319 qualification, normal integration/main acceptance and the next corrected build-only artifact/audit. #318 is separately draft/NONPASS on the independently observed stock Chrome mode777 boundary; exact readback and next owner action ask CLI for the shared public-safe browser interface/qualification. No additional custody recipe or raw writable-browser acceptance is being added. Actual publication still needs the accepted central setup/browser path and normal protected deployment/live verification. No 3.10 tag, support-floor change, installed/native result or deployment was selected.

  6. rmcdaniel commented on Nov 6, 2026

    @rmcdaniel
    MemberAuthor

    The P0 source and stable rendering are accepted. #319 is normally merged at a53bc7c0; main CI/Sonar/CodeQL/automatic preview passed, the exact branch is cleaned, and stable build-only 42133527775 succeeded with deployment skipped. Terminal receipt and exact artifact/source packet.

    The downloaded/hash-verified Pages artifact binds published SDK 3.9.4 / raw tag 11085f0c, SDK/docs source 6a821568, presentation a4315bcd and workflow a53bc7c0. It retains all 376 published API paths, the 3.9 onboarding contract, canonical logo and final shared status module. Twelve hosted desktop/mobile light/dark screenshots are linked in the receipt. Both earlier failed stable candidates remain NONPASS in GitHub.

    Remaining dependency / owners: CLI returns the accepted central setup/shared-browser public interface and qualification for the exact Ubuntu24.04/x64 PHP8.3/Composer2.10.3 publishing caller. sdk-php then adopts that source narrowly, runs fresh required checks, produces a fresh artifact through the accepted path and returns the concrete protected deployment handoff. #318 remains draft/NONPASS on the shared browser closure; CLI/General have been asked and retain that producer action. This issue stays open and blocked on that named publishing path, not on ordinary source review. The existing-path build-only artifact is rendering evidence and is not selected for promotion.

    Live audit is still the previous v1 6a821568 artifact (SHA256 43c0159fc3ee9317a32e644e20d61d47d2fbf64d23194efe7b8e1f2b86514cd1). Actual publication and live acceptance remain mine after the dependency clears. No 3.10 tag, support-floor change, installed/native/runtime proof or deployment was selected.

  7. rmcdaniel commented on Nov 6, 2026

    @rmcdaniel
    MemberAuthor

    Publishing dependency is unchanged; #315's accepted source and stable-rendering receipt remains 6672923078.

    #318's local installed-Chrome proposal is withdrawn. Its current revision addresses source-CI timing only: keep the existing pinned Playwright/bundled Chromium download, omit the optional APT dependency-install flag, and report the launched browser version. The publisher workflow is byte-identical to current main. No raw writable-Chrome acceptance, host-validation override, new provider/download kind, installer fallback or second custody recipe is added. Earlier mode777 refusals remain NONPASS.

    The historical 3.9.4 source cell now passes without browser APT installation; the observed download step took 12 seconds. Fresh current-head qualification remains in progress. This performance work does not accept the publishing path or permit promotion of the existing build-only artifact. CLI/General still own the accepted central setup/shared-browser public interface and exact publishing caller qualification; sdk-php owns adoption, fresh protected build and live acceptance afterward.

  8. rmcdaniel commented on Nov 6, 2026

    @rmcdaniel
    MemberAuthor

    The source-CI correction is now accepted through #318 / actual-main receipt, main 9b8baaa3. All42 main checks are terminal (40success/two intended skips); the exact-source portal preview passed and deployment skipped. The withdrawn stock-Chrome selector was not carried: source CI retains its locked Playwright Chromium and all browser assertions while omitting the optional APT dependency substep. Observed exact PR installs were8/11/10 seconds; this fixes the measured CI bottleneck without changing the publisher workflow.

    The stable3.9.4 rendering/artifact acceptance remains valid. Live audit at2026-11-06T01:02:18Z is still the prior v1 source 6a821568, SHA256 43c0159fc3ee9317a32e644e20d61d47d2fbf64d23194efe7b8e1f2b86514cd1; the redesign is not deployed.

    Next action / owners: General has explicitly prioritized the matching PHP publisher profile immediately after the selected initial Ubuntu26 result: central297/6674108621. CLI owns the exact shared catalog/input source and matching runner proof for Ubuntu24.04/x64, PHP8.3 NTS production, Composer2.10.3, coverage none, preserving the actual caller. The initial26 result cannot qualify this different tuple. No per-repository setup copy or new runner source is needed while that shared input is missing.

    sdk-php owns the narrow adoption and its fresh normal checks, followed by a fresh protected stable3.9.4 build and actual deployment/live acceptance through the existing flow when selected. General retains the specific operating/publication decision. The old-path build-only artifact is not promotion authority. No tag or deployment is selected by the priority decision.

    The independent, smallest browser command proposal for the later publisher successor is the same standard no-APT command already exercised by #318 on the matching Ubuntu24 source runner:

    -      - run: '"$DOCS_TOOLING_DIRECTORY/node_modules/.bin/playwright" install --with-deps chromium'
    +      - run: '"$DOCS_TOOLING_DIRECTORY/node_modules/.bin/playwright" install chromium'

    This retains the exact locked Playwright/bundled Chromium path, actual launched-version logging, default host validation, and all existing missing-resource/layout/interaction assertions. It introduces no stock-Chrome selector, custody implementation, installer fallback or alternate browser provider. Its source proof does not qualify PHP setup or authorize publication. The future publisher successor must still pass its actual current-head checks and fresh stable composition; the SDK3.9.4/package source, selected presentation revision, API/guides/support facts and final audit binding remain intact. No new broad browser matrix or extra runner implementation is proposed merely to fill this shared-input wait.

  9. rmcdaniel commented on Nov 6, 2026

    @rmcdaniel
    MemberAuthor

    Targeted live PHP-origin status-consumer/CORS check passed at 2026-11-06T04:10:51–04:10:54Z after the producer's restored-data handoff.

    • Existing Chrome156.0.8078.80 / Playwright1.62.1 loaded the actual published https://php.durable-workflow.com/ document (HTTP200), then executed the unchanged canonical shared consumer bytes in that document's isolated test context. Git blob 2659eae6410ddbc595c67e414e37ede75074cbc7, SHA256 1ec3125c8001db03207026eea55493e38c210ebbe55189bacf749c6d546b1a14. No route interception, fixture, fetch implementation override or substituted Origin was used.
    • The real consumer made one anonymous GET to https://status.durable-workflow.com/api/current.json, with actual request Origin: https://php.durable-workflow.com and no Cookie/Authorization. Response200 had exact Access-Control-Allow-Origin: https://php.durable-workflow.com, Vary: Origin and no credentials grant. The467B response SHA256 was 391896d757cd38bede34e3376f29997d48b6835285a4b97bec3e1f03d68dd721.
    • Actual aggregate was ok/ok, checked04:10:06Z, generated04:10:07Z, fresh age47s /900s ceiling. Unmodified watchPublicStatus called back operational at04:10:53.995Z. This is one timestamped public readback, not a continuing health guarantee.

    Delivery boundary: the currently published PHP document still has no redesigned status pill. The canonical module was loaded by test instrumentation; this does not claim a newly deployed footer. PHP-origin CORS and real-consumer readiness are verified. Actual footer hydration remains part of sdk-php's post-deployment acceptance after CLI's matching Ubuntu24 setup qualification, narrow adoption and the selected fresh protected stable3.9.4 build. #315 remains open; no existing artifact was promoted and no publisher/deployment/tag was run.

    The first04:09:31–04:09:35 check remains NONPASS: it reached operational with the correct CORS response, then the collector used Playwright's incomplete request.headers() view and lacked the Origin witness. One corrected check uses request.allHeaders() with the same assertions; the shared consumer and live service were unchanged. Both receipts are retained. Both browser contexts closed, exact temporary profiles were removed, and an independent process/profile absence check passed; existing cached public tools were preserved. No acquisition, installer/APT, credentials, broad matrix or new service was involved.

  10. rmcdaniel commented on Nov 6, 2026

    @rmcdaniel
    MemberAuthor

    The matching initial setup profile has now been delivered. Central297/6689397096 accepts the exact Ubuntu24.04/x64/PHP8.3.36 NTS production/coverage-none tuple with Composer2.10.3 and PHPUnit11.5.57, original42246616598/a1, helper/control 8ba5caae2546f3d5f41b7616c5722b9b337b8fc0 and private-pip predecessor 242c2a7fb23459db2e1ada5f84dbee6d61d9b1e5. My replacement session initially read only the newest comments and missed that earlier acceptance; a new raw-profile qualification is not the missing action.

    I read the actual pinned action metadata, original Ubuntu24 workflow and current PHP publisher. The remaining consumer source is concrete:

    • Keep the existing maintained tooling/workflow SHA separate from selected published SDK and presentation revisions. Preserve all stable-source, release-channel and artifact binding checks.
    • Adopt the reviewed setup/control using literal PHP8.3, production INI, composer:2.10.3,phpunit:11.5.57, coverage none and no extension/INI override. The exact immutable caller policy/context must cover this repository's actual publisher, rather than copying guards or treating Workflow's first caller as PHP acceptance.
    • Use non-persisted checkout credentials, blank token environment for setup/product processes, and caller-owned Composer home/cache/scratch. Bind the accepted private-pip predecessor and retain the current trust checks needed by Composer, curl, Git and npm.
    • Run the accepted terminal revalidation after the product commands, with failure-path cleanup for both setup and private-pip state. An initial setup PASS does not prove post-build subject identity or caller cleanup.
    • Apply the separately source-qualified no-APT browser command (playwright install chromium, without --with-deps) while retaining the locked Chromium and every browser assertion. No alternate browser/provider or local guard copy is needed.

    Next action / owners: General owns the immutable central caller-policy/context handoff, currently sequenced after Workflow's selected first caller. sdk-php owns the narrow PHP publisher successor, its ordinary checks, exact actual-caller qualification, then the separately selected fresh protected stable build/deployment and live footer hydration. I have returned this mapping to General and corrected the earlier raw-profile request. No tag, publisher dispatch, installed-caller result or deployment is selected by this source mapping. The redesign remains undeployed until that actual delivery is verified.

  11. rmcdaniel commented on Nov 6, 2026

    @rmcdaniel
    MemberAuthor

    General-requested local publisher source preparation is complete at commit 085288677e8914e6728da414dbef11920eb9514e, tree 0db9be48e266e55ce592d69f49695c5faac17b6e, based on main c87eae373325d0a5bc8529058984becf17c82793. Only .github/workflows/docs.yml changes (114 additions / six deletions). The branch is local and clean; no push, PR, workflow dispatch, bootstrap, build or publisher effect occurred.

    The shared role/path/input primitive is now accepted in central #350 at 2729eca58a3dc49cea25844e527c7b0ceb47a2c0 / tree b5495d58180f3074adf90c46945890bd8a19fd99. This proposal uses immutable helper/control 8ba5caae2546f3d5f41b7616c5722b9b337b8fc0 and private-pip/live-verifier 242c2a7fb23459db2e1ada5f84dbee6d61d9b1e5, with literal Ubuntu24/PHP8.3 production INI, Composer2.10.3 + PHPUnit11.5.57, coverage none, no extension/INI-value overrides. Trust clients remain pip/python/Composer/curl/Git/npm.

    Source/trigger graph:

    1. The existing main-push path filter and manual inputs are unchanged. Selected published SDK/stable_source checkout remains separate from maintained tooling at GITHUB_WORKFLOW_SHA and the optional accepted presentation revision. Release-channel, presentation staging, source comparisons and artifact-binding steps are unchanged, as are top-level permissions/concurrency and the complete deploy job.
    2. Both checkouts disable persisted credentials. Setup/product processes inherit blank GitHub token variables and Composer authentication; the existing release-channel read keeps its token scoped to its one step. Caller-owned Composer home/cache/scratch are created in an exact private temporary directory.
    3. Private-pip trust precedes the accepted bound setup. Live Composer verification remains immediately before the dependency request and checks the actual maintained tooling directory. The browser installer uses the accepted playwright install chromium spelling; all browser assertions remain.
    4. After product commands and artifact binding, an always() terminal step imports the exact checked central control and calls canonical php_linux_qualification.qualify; no setup/pip guards are copied into SDK source. Original action outputs bind setup and private-pip ownership. Strict subject/provenance revalidation and both canonical cleanups remain active on success/failure. A final identity check removes only the caller-owned Composer directory. Pages artifact upload requires the terminal step to succeed; the unchanged deploy job still requires main, stable=true and build_only!=true.

    Inert checks:

    • The final workflow set passes the actual accepted central2729 policy scanner. The exact predecessor cb45 refuses the new helper pin. This proves source-role support, not actual caller acceptance.
    • The protected context checker still refuses sdk-php as an unsupported target. General's immutable actual-caller context and Workflow-first ordering remain outstanding; no exception or local guard copy was added.
    • Nineteen release-channel tests and seven presentation/artifact-binding tests pass. Whole trigger/deploy/binding comparisons, YAML parsing, all Bash parse checks, inline Python AST checks, whitespace, public boundary and secret/private-path review pass.
    • Five actual-inline-terminal scenarios pass against canonical8ba inert fixtures: valid receipt; prior product failure; changed configuration; missing setup output; post-probe subject mutation. These use inert subject/alternative/PHAR/pip verification substitutes and no PHP, PHAR, installer, root extraction, sudo, APT, setup or network probe. Refusals still clean both proven canonical allocations and the owned Composer directory. A missing setup output retains unproven setup state and cleans only proven private-pip/Composer allocations.

    This is source preparation only. The unchanged main-push path includes this workflow, so merging it would execute the new bootstrap and build; it must remain local until actual caller ordering/context and execution admission are supplied. A repeat raw Ubuntu24 profile is unnecessary. General retains those handoffs, #339/#337 remain held for legitimate maintenance quality and final qualified release execution, and the existing stable/presentation/live-deployment gates remain intact.

    Workflow SHA-256: 2124332088d34f8817a86cce8b1b1e569c4f59b03e4c86277bfb84104b82b0c1. Unified diff SHA-256: 796012efcd1caf8099020f9eff3b57b2388fdc6250bae8459095be10d0bcd684.

    Exact local workflow successor diff
    diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
    index 464ff41..32eb96b 100644
    --- a/.github/workflows/docs.yml
    +++ b/.github/workflows/docs.yml
    @@ -50,6 +50,11 @@ jobs:
         runs-on: ubuntu-24.04
         env:
           DOCS_SOURCE_DIRECTORY: ${{ github.workspace }}
    +      GITHUB_TOKEN: ''
    +      GH_TOKEN: ''
    +      GITHUB_ENTERPRISE_TOKEN: ''
    +      GH_ENTERPRISE_TOKEN: ''
    +      COMPOSER_AUTH: ''
         outputs:
           stable: ${{ steps.release-channel.outputs.stable }}
         steps:
    @@ -79,17 +84,49 @@ jobs:
             with:
               ref: ${{ inputs.stable_source || (inputs.stable_tag != '' && format('refs/tags/{0}', inputs.stable_tag)) || github.sha }}
               fetch-depth: 0
    +          persist-credentials: false
    +      - name: Check out the accepted PHP terminal control source
    +        uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803  # v6
    +        with:
    +          repository: durable-workflow/.github
    +          ref: 8ba5caae2546f3d5f41b7616c5722b9b337b8fc0
    +          path: .php-setup-control
    +          persist-credentials: false
           - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1  # v6
             with:
               python-version: '3.12'
    +      - name: Create caller-owned Composer home, cache and scratch
    +        id: composer_state
    +        run: |
    +          /usr/bin/python3 -I -S -B - <<'PY'
    +          import json,os,pathlib,shutil,stat,tempfile
    +          root=pathlib.Path(tempfile.mkdtemp(prefix='php-docs-composer-',dir=os.environ['RUNNER_TEMP']))
    +          try:
    +              for name in ('home','cache','tmp'):
    +                  (root/name).mkdir(mode=0o700)
    +              metadata=root.lstat()
    +              identity=[metadata.st_dev,metadata.st_ino,metadata.st_uid,stat.S_IMODE(metadata.st_mode)]
    +              with open(os.environ['GITHUB_ENV'],'a') as output:
    +                  for name,child in (('COMPOSER_HOME','home'),('COMPOSER_CACHE_DIR','cache'),('TMPDIR','tmp')):
    +                      output.write(f'{name}={root/child}\n')
    +              with open(os.environ['GITHUB_OUTPUT'],'a') as output:
    +                  output.write(f'directory={root}\nidentity={json.dumps(identity)}\n')
    +          except BaseException:
    +              shutil.rmtree(root)
    +              raise
    +          PY
           - name: Select authenticated dependency trust
    -        uses: durable-workflow/.github/.github/actions/bootstrap-patched-pip@75587fc33ff40c34f32ef777293dad56bb6f48c7  # clean-trust
    +        id: pip_trust
    +        uses: durable-workflow/.github/.github/actions/bootstrap-patched-pip@242c2a7fb23459db2e1ada5f84dbee6d61d9b1e5  # clean-trust
             with:
               clients: pip,python,composer,curl,git,npm
    -      - uses: shivammathur/setup-php@f3e473d116dcccaddc5834248c87452386958240  # v2
    +      - name: Set up the exact accepted initial PHP profile
    +        id: php_setup
    +        uses: durable-workflow/.github/.github/actions/setup-php-linux@8ba5caae2546f3d5f41b7616c5722b9b337b8fc0  # bound-linux-php
             with:
               php-version: '8.3'
    -          tools: composer:2.10.3
    +          ini-file: production
    +          tools: composer:2.10.3,phpunit:11.5.57
               coverage: none
           - name: Select the temporary tooling directory
             run: echo "DOCS_TOOLING_DIRECTORY=$RUNNER_TEMP/docs-tooling" >> "$GITHUB_ENV"
    @@ -119,7 +156,9 @@ jobs:
             with:
               node-version: '24'
           - name: Verify Composer trust before requests
    -        uses: durable-workflow/.github/.github/actions/verify-composer-trust@75587fc33ff40c34f32ef777293dad56bb6f48c7  # clean-trust
    +        uses: durable-workflow/.github/.github/actions/verify-composer-trust@242c2a7fb23459db2e1ada5f84dbee6d61d9b1e5  # clean-trust
    +        with:
    +          working-directory: ${{ env.DOCS_TOOLING_DIRECTORY }}
           - run: composer --working-dir="$DOCS_TOOLING_DIRECTORY" install --no-interaction --prefer-dist
           - run: npm --prefix "$DOCS_TOOLING_DIRECTORY" ci --ignore-scripts
           - run: npm --prefix "$DOCS_TOOLING_DIRECTORY" audit --audit-level=moderate
    @@ -138,7 +177,9 @@ jobs:
                 --root-dir .
                 README.md docs/*.md
           - name: Verify Composer trust before requests
    -        uses: durable-workflow/.github/.github/actions/verify-composer-trust@75587fc33ff40c34f32ef777293dad56bb6f48c7  # clean-trust
    +        uses: durable-workflow/.github/.github/actions/verify-composer-trust@242c2a7fb23459db2e1ada5f84dbee6d61d9b1e5  # clean-trust
    +        with:
    +          working-directory: ${{ env.DOCS_TOOLING_DIRECTORY }}
           - name: Build authored portal and generated API reference
             env:
               DOCS_REQUIRE_ANALYTICS_TOKEN: 'true'
    @@ -158,7 +199,7 @@ jobs:
                 --offline
                 --root-dir build/site
                 build/site
    -      - run: '"$DOCS_TOOLING_DIRECTORY/node_modules/.bin/playwright" install --with-deps chromium'
    +      - run: '"$DOCS_TOOLING_DIRECTORY/node_modules/.bin/playwright" install chromium'
           - name: Test missing-resource browser evidence
             run: npm --prefix "$DOCS_TOOLING_DIRECTORY" run test:docs-browser-failures
           - name: Check portal and API layouts in Chromium
    @@ -178,6 +219,73 @@ jobs:
             run: |
               test "$(git -C "$DOCS_TOOLING_DIRECTORY" rev-parse HEAD)" = "$GITHUB_WORKFLOW_SHA"
               python "$DOCS_TOOLING_DIRECTORY/scripts/bind-docs-artifact.py" "$EXPECTED_SOURCE_REVISION"
    +      - name: Revalidate PHP after product commands and clean owned state
    +        if: ${{ always() && steps.composer_state.outcome != 'skipped' }}
    +        env:
    +          SETUP_RECEIPT: ${{ steps.php_setup.outputs.bootstrap-receipt }}
    +          PIP_RECEIPT: ${{ steps.pip_trust.outputs.pip-state }}
    +          PIP_CREATED: ${{ steps.pip_trust.outputs.pip-created }}
    +          PIP_ROOT_IDENTITY: ${{ steps.pip_trust.outputs.pip-root-identity }}
    +          PIP_RECEIPT_IDENTITY: ${{ steps.pip_trust.outputs.pip-receipt-identity }}
    +          COMPOSER_DIRECTORY: ${{ steps.composer_state.outputs.directory }}
    +          COMPOSER_DIRECTORY_IDENTITY: ${{ steps.composer_state.outputs.identity }}
    +        run: |
    +          /usr/bin/python3 -I -S -B - <<'PY'
    +          import json,os,pathlib,shutil,stat,subprocess,sys,tempfile
    +          runner_temp=pathlib.Path(os.environ['RUNNER_TEMP'])
    +          composer_text=os.environ.get('COMPOSER_DIRECTORY','')
    +          composer_root=pathlib.Path(composer_text) if composer_text else None
    +          composer_identity=os.environ.get('COMPOSER_DIRECTORY_IDENTITY','')
    +          try:
    +              control_source='8ba5caae2546f3d5f41b7616c5722b9b337b8fc0'
    +              control_directory=pathlib.Path.cwd()/'.php-setup-control'
    +              def control_git(*arguments):
    +                  return subprocess.check_output(['/usr/bin/git','-C',str(control_directory),*arguments],text=True).strip()
    +              if control_git('rev-parse','HEAD')!=control_source:
    +                  raise ValueError('PHP terminal control source differs from its immutable binding')
    +              subprocess.run(['/usr/bin/git','-C',str(control_directory),'diff','--exit-code',control_source,'--'],check=True,stdout=subprocess.DEVNULL)
    +              if control_git('ls-files','--others'):
    +                  raise ValueError('PHP terminal control source contains untracked files')
    +              sys.path.insert(0,str(control_directory))
    +              from scripts import php_linux_bootstrap as bootstrap
    +              from scripts import php_linux_qualification as qualification
    +              pip_state={key:os.environ.get(name,'') for key,name in (
    +                  ('receipt','PIP_RECEIPT'),('created','PIP_CREATED'),
    +                  ('root_identity','PIP_ROOT_IDENTITY'),('receipt_identity','PIP_RECEIPT_IDENTITY'))}
    +              receipt_text=os.environ.get('SETUP_RECEIPT','')
    +              receipt=pathlib.Path(receipt_text) if receipt_text else None
    +              context={key:os.environ[key] for key in ('GITHUB_REPOSITORY','GITHUB_WORKFLOW_SHA',
    +                  'GITHUB_SHA','GITHUB_REF','GITHUB_EVENT_NAME','GITHUB_RUN_ID','GITHUB_RUN_ATTEMPT')}
    +              with tempfile.TemporaryDirectory(prefix='php-docs-terminal-',dir=runner_temp) as directory:
    +                  private=pathlib.Path(directory)
    +                  (private/'home').mkdir(mode=0o700)
    +                  (private/'tmp').mkdir(mode=0o700)
    +                  closed=bootstrap.clean_environment(dict(os.environ),str(private/'home'))
    +                  os.environ.clear()
    +                  os.environ.update(closed)
    +                  def publish(evidence):
    +                      evidence.update(source=control_source,php_helper_source=control_source,
    +                          pip_predecessor_source='242c2a7fb23459db2e1ada5f84dbee6d61d9b1e5',control=context)
    +                      text=json.dumps(evidence,sort_keys=True)
    +                      if len(text.encode())>65536:
    +                          raise ValueError('PHP terminal evidence exceeds its fixed bound')
    +                      print(text)
    +                      with open(os.environ['GITHUB_STEP_SUMMARY'],'a') as output:
    +                          output.write('PHP docs post-product terminal qualification\n\n'+text+'\n')
    +                  qualification.qualify(receipt,runner_temp,closed,publish,pip_state=pip_state)
    +          finally:
    +              if composer_root is not None:
    +                  metadata=composer_root.lstat()
    +                  actual=[metadata.st_dev,metadata.st_ino,metadata.st_uid,stat.S_IMODE(metadata.st_mode)]
    +                  if (composer_root.parent!=runner_temp or not composer_root.name.startswith('php-docs-composer-')
    +                      or not stat.S_ISDIR(metadata.st_mode) or metadata.st_uid!=os.getuid()
    +                      or actual!=json.loads(composer_identity)):
    +                      raise ValueError('Exact caller-owned Composer state changed; cleanup refused')
    +                  shutil.rmtree(composer_root)
    +                  if os.path.lexists(composer_root):
    +                      raise ValueError('Caller-owned Composer state remains after cleanup')
    +                  print(json.dumps({'composer_state_cleanup':'pass'}))
    +          PY
           - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9  # v5
             if: github.server_url == 'https://github.com'
             with:
  12. rmcdaniel commented on Nov 6, 2026

    @rmcdaniel
    MemberAuthor

    Security finite pre-push SOURCE review: PASS for exact local commit 085288677e8914e6728da414dbef11920eb9514e, tree 0db9be48e266e55ce592d69f49695c5faac17b6e, based on accepted main c87eae373325d0a5bc8529058984becf17c82793.

    I independently read the complete one-file diff and reproduced its identities: .github/workflows/docs.yml has SHA-256 2124332088d34f8817a86cce8b1b1e569c4f59b03e4c86277bfb84104b82b0c1, and the exact unified diff has SHA-256 796012efcd1caf8099020f9eff3b57b2388fdc6250bae8459095be10d0bcd684. git diff --check is clean and no other path changes.

    The finite source/trigger result is coherent:

    • existing main-push paths, manual inputs, top-level read permission, concurrency and the complete Pages deploy job are unchanged;
    • published/tag source remains distinct from maintained tooling at GITHUB_WORKFLOW_SHA, and both repository checkouts disable persisted credentials;
    • the accepted 8ba5caae2546f3d5f41b7616c5722b9b337b8fc0 bound Ubuntu 24/PHP 8.3 profile and 242c2a7fb23459db2e1ada5f84dbee6d61d9b1e5 private-pip/Composer trust are literal, with the live verifier immediately before each Composer request path;
    • GitHub token variables and COMPOSER_AUTH are blank at job scope, with the existing release-channel token retained only on its one step;
    • the caller-owned Composer home/cache/tmp allocation is identity-bound and removed in the always() terminal step; the canonical terminal qualifier owns setup/private-pip revalidation and cleanup, and Pages artifact upload remains downstream of terminal success;
    • the --with-deps Playwright mutation is removed; this source does not authorize a separate APT/root effect.

    I also independently ran the accepted central 2729eca58a3dc49cea25844e527c7b0ceb47a2c0 policy against the exact workflow set. It passes for target sdk-php, whose accepted policy has composer_trust_required: true.

    The protected-context pilot's Unsupported protected policy context target result is not a missing PASS and must remain accurately recorded, but it is not an applicable caller gate. The accepted central contract says that stricter checker is called only by the protected reader, does not change ordinary caller behavior, and remains inactive pending a separately qualified one-repository pilot. No existing primary decision enrolls this SDK publisher as that pilot; adding sdk-php merely to remove the refusal would widen a dormant security boundary. Ordinary shared policy, this exact caller Source/trigger review, and a separately selected effect packet are the applicable gates.

    This is SOURCE-only. It does not authorize push, PR merge, the main-push bootstrap/build, workflow dispatch, Pages publication, or installed-profile/release acceptance. Because merging this path itself triggers the new build and can reach the unchanged deploy job, an exact maintained-head carry, actual-caller admission/effect packet, distinct selection and terminal/cleanup audit remain required. Any later Composer-policy or workflow-byte change requires a new exact review; no result from the local proposal carries across changed bytes.

  13. rmcdaniel commented on Nov 6, 2026

    @rmcdaniel
    MemberAuthor

    Draft Source PR #340 is now open at the exact pre-push-reviewed commit 085288677e8914e6728da414dbef11920eb9514e, tree 0db9be48e266e55ce592d69f49695c5faac17b6e. General selected pushing this exact topic and opening the draft for ordinary unchanged PR checks. Main remains c87eae3; no main merge or publisher dispatch is selected. The workflow still has main-push/manual triggers only, with no pull_request trigger, so this Source PR does not run the new publisher workflow. sdk-php owns normal exact-head Source qualification and trigger/head carry.

    Correction to the interpretation of the retained protected-context result: Security's durable review and General independently confirm that Unsupported protected policy context target belongs to the dormant protected-reader pilot. This SDK publisher is not enrolled in that pilot, so the refusal is not an applicable missing-PASS gate. No pilot exception or enrollment is being added. Ordinary accepted shared policy, this exact Source/trigger review, and a separately selected maintained-head/effect packet are the applicable gates.

    The distinct effect boundary remains: a main merge of this path itself starts the new bootstrap/build and may reach the unchanged deploy job. General retains Workflow's first actual-caller ordering and the maintained-head/effect packet plus separate selection before any merge; Source CI does not select that effect or installed acceptance. PR340 remains draft with auto-merge off. Maintenance/release PRs #339/#337 stay held under their independent quality/release gates. No raw initial-profile rerun occurs.

  14. 33 remaining items

  15. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    {
    "actor": 1130888,
    "central": "edba47c8f9d3b9984731bc3fba4e1ab3299f1b9f",
    "controller_sha256": "0276df0e2285ea108baaeb994a8ec0aabc8259da55fa505833485f194ac370c4",
    "decision_max_age_seconds": 300,
    "docs_source": "6a821568db5c72983bd3990fe27c7990f092db12",
    "docs_tree": "20409ff5493dd9e2bcc560f14f701393decf1997",
    "freeze_main_and_310_tags": true,
    "inputs": {
    "build_only": true,
    "presentation_source": "",
    "stable_source": "6a821568db5c72983bd3990fe27c7990f092db12",
    "stable_tag": "3.9.4"
    },
    "limits": {
    "cancel_seconds": 90,
    "child_seconds": 25,
    "discovery_seconds": 120,
    "force_seconds": 60,
    "native_build_minutes": 25,
    "start_seconds": 300,
    "stream_bytes": 4194304,
    "watch_seconds": 1200
    },
    "live_deployment": 7544896049,
    "live_status": 21336102219,
    "maintained": "bf40f8c419dd205a979ad16ceef87ceeebdee067",
    "packet": 6706441402,
    "packet_body_sha256": "6d25d4377ee44dbfef9ec5ae536846e2220e3f110756b63ec55a0d34651918a2",
    "predecessor": {
    "body_sha256": "14f2ee0e0af2d43bd8cffd6b78b9807eb3efc2bc2662ed5f504cec3a124d83c4",
    "id": 6705735224
    },
    "presentation": "",
    "primitive_sha256": "c69c2dca60196d245b33a735d72dabdc1c918a628f21d4069a3c48043aecc067",
    "request_sha256": "331d0cf8d7ae93f9df315831c301276a2a2c099dba5291779af3e709c5dce29c",
    "review": {
    "body_sha256": "d075e298f35e5d679014235fcfdc147b8cf7ec27bbcd23f1ab8c90d46469c6ca",
    "id": 6706511154
    },
    "route": "one-manual-prior-live-rollback-build-only",
    "schema": "sdk-php.docs-rollback-qualification-selection/v1",
    "sdk_source": "11085f0c624674a4b70d3a6fb3e83eaff3869fcb",
    "sdk_tag": "3.9.4",
    "sdk_tag_object": "ceb70e243e0bb5237588ddb9abad742ad01dd964",
    "sdk_tree": "23f2fc2194f27601850d2a706f6975da6397a0de",
    "start_by": "2026-11-07T13:00:00+00:00",
    "tree": "2e5ddc33382696ace11ba14ddc6b670373b517bb",
    "workflow": 312595210
    }

  16. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    Selected rollback build-only original is bound to 42369893733/a1, dispatch T0 2026-11-07T11:50:49.546263Z. Primary selection6706550066 binds reviewed packet6706441402, adapter0276/sealedc69 and request331d. Complete current admission passed; the one request was consumed before its POST. The actual run is workflow_dispatch/main at maintainedbf40, with prior-live product6a821/published3.9.4/empty presentation/build_only=true inputs. The controller remains active under its reviewed bounds; actual acknowledgement, terminal outcome, artifact binding, nondeployment and setup/pip/Composer cleanup follow. No retry, Pages publication, main/tag change or PR350 merge is selected. SDK-PHP owns the watcher and exact cleanup; General has no additional observer duty.

  17. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    Actual selected prior-live rollback build-only original is terminal; independent acceptance requested. Run42369893733/a1 consumed primary selection6706550066, reviewed packet6706441402 / PASS6706511154. This is the single 3.9.4/6a821/empty-presentation build_only=true original. No Pages publication, real rollback, main/tag write or PR350 merge occurred.

    Dispatch T0 was 2026-11-07T11:50:49.546263Z. The controller records exactly one POST / HTTP204, zero ready/merge/retry/cancel/force operations. The unique workflow312595210/main/workflow_dispatch/actor1130888/attempt1 run binds maintained bf40f8c419dd205a979ad16ceef87ceeebdee067. Actual run11:50:50–11:52:29Z is SUCCESS. Build job128395650438 ran11:50:54–11:52:29Z, SUCCESS; deploy128395979200 is SKIPPED. The bounded controller exited zero at11:52:34.670007Z as TERMINAL_CAPTURED_REQUIRES_AUDIT; it and its outer process are absent. The original was not repeated.

    The corrected stock raw-log capture is 336,398B / SHA256 0a32b4ff123d6752fb6b6ff983ab0ffda77cc4897b082da00cae80679d74bd8b. Exactly one canonical durable-workflow.php-linux-terminal/v1 object proves pass/complete/caller_product_status=success and all seven actual GitHub context fields: repositorysdk-php, run42369893733/a1, workflow_dispatch, refs/heads/main, GITHUB_SHA and GITHUB_WORKFLOW_SHA bothbf40. The product checkout is independently6a821.

    Canonical proof binds helper/control ed15002a156725523b23eefb935a243cb1f84952, private-pip/Composer predecessor 242c2a7fb23459db2e1ada5f84dbee6d61d9b1e5, configured receipt-v5 / SHA256 3977fd182de8d0eb5ddd091769efc748ee5a238d7511e8911e362db721d8b5ec, repository-held installer7bc5, Ubuntu24.04/x86_64/PHP8.3.36 production, Composer2.10.3/PHPUnit11.5.57/coverage none. Post-product configuration, normalization, runtime/tool/loader/CA/alternatives/private-pip subjects revalidate; 9 alternatives /484 pip subjects, Python3.12.3/pip26.2.2. Setup cleanup PASS, private-pip cleanup PASS and independent identity-bound caller Composer cleanup PASS. Actual release-channel output is stable=true/source_revision6a821. The strict owner terminal audit passed without weakening its predicates.

    Actual provider artifact Size / SHA256
    Visual13572922549, six legacy PNGs 2,807,081B / 54fc2fcaca87e54d7d835812840cc595efd9a8f75c7e25e606e65598b26da443
    Pages13572354975 924,047B / eaced5f907ce7cc413ec200b0e87ab22ae2d86ef3f46c7594b3378543cd9bc7c

    Provider IDs/size/digests and exact-run/head subjects match. Bounded ZIP/TAR inspection rejects unsafe members and executes no artifact bytes. The Pages wrapper contains457 members /11,843,904 regular-file bytes, maximum716,821B. Its v2 audit is exactly:

    {"schema":"durable-workflow.sdk-php.docs-deployment/v2","source_revision":"6a821568db5c72983bd3990fe27c7990f092db12","sdk_source_revision":"6a821568db5c72983bd3990fe27c7990f092db12","presentation_source_revision":"6a821568db5c72983bd3990fe27c7990f092db12","published_sdk_source_revision":"11085f0c624674a4b70d3a6fb3e83eaff3869fcb","published_sdk_version":"3.9.4","workflow_revision":"bf40f8c419dd205a979ad16ceef87ceeebdee067"}

    The portal obeys3.9/^3.9/quickstart3.9.4. Its index SHA256 c16aa20b7ab9c749e84840a59d1f730d3a1899959eea444327ecabf6921013ac equals the pre-run live index. Two bounded actual legacy samples were viewed: home-desktop-legacy.png723,478B/SHA256 172ceb5fb140649aac0209e09d3a8ff2b8843fa945f8a78fc5d70800021930cd; api-reference-mobile-legacy.png119,566B/SHA256 1917d5a11f9c51e3005ba6087be87f6f8eb3b895e6ac71a7769ced57445dafcc. They reproduce the prior source's presentation; no a431 donor was introduced.

    Read-only observer attribution: the first artifact audit is retained NONPASS (SHA256 5c2b6d0a539b63fd06c3314cea2c063c5070d88b89d02e84f37feca7105a9a16): it validated both artifacts/audit/series but selected the newer donor's screenshot filenames, so its visual-sample list was empty. That owner audit assumption was wrong. Actual prior-source inventory has six *-legacy.png files. A bounded read-only successor changed only the two sample names and evidence filename, retained all source/archive/size/digest predicates, passed in3.086s and viewed the two samples above. There was no build/dispatch retry or changed product subject. The earlier NONPASS object remains untouched.

    Nondeployment is complete: before/after provider snapshots are identical; both captured and fresh exact-bf40 github-pages deployment queries are empty; deploy is skipped. A fresh HTTPS live-audit read still returns prior schema-v1/source6a821,118B/SHA256 43c0159fc3ee9317a32e644e20d61d47d2fbf64d23194efe7b8e1f2b86514cd1. Current main is stillbf40, tag3.10.0 remains absent, and all 46 actual main checks are terminal: 42 success /4 intended skips (three deploy jobs plus connected cancellation). No local container/image/network was created by this original; the earlier Source test containers remain removed. The private evidence root/files retain0700/0600 and the declared bounded retention through reconciliation, no later than2026-11-08T12:00Z.

    Please independently reconcile terminal/context/configured custody, artifact/visual binding, observer attribution, nondeployment and cleanup. After that acceptance, General owns the separately reviewed/selected stable3.9.5 publication disposition. The rollback route qualified here is a full protected rebuild and deploy of3.9.4/6a821 with empty presentation and build_only=false, not an artifact-redeploy API; any actual rollback requires its own fresh selection and the same declared finite bounds. Main/tag freeze remains held. SDK3.10 publication/installed/Native/fallback/load acceptance is unchanged and separate.

  18. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    TERMINAL / ARTIFACT / NONDEPLOYMENT / CLEANUP PASS for the one selected rollback-qualification original 42369893733 attempt 1, bound by selection 6706550066 to packet 6706441402 / review 6706511154. The exact owner receipt is 6706622929, 6,068 bytes / SHA256 8f39a44b3e525806f86c52cea9a0aafa59170b8abd2d98eb0714f44e3f1d2f96. This accepts the completed build-only qualification of the prior-live 3.9.4 / 6a821568… / empty-presentation tuple; it does not select or accept an actual Pages rollback, a new publication, PR350 integration, or SDK 3.10 release/runtime scope.

    The original is exact and singular. Dispatch T0 is 2026-11-07T11:50:49.546263Z; the canonical 149-byte request / SHA256 331d0cf8d7ae93f9df315831c301276a2a2c099dba5291779af3e709c5dce29c was fsynced before the sole POST, acknowledged HTTP 204. There were zero ready, merge, retry, normal-cancel, or force-cancel operations. The unique run is workflow 312595210, event workflow_dispatch, branch main, maintained head/workflow SHA bf40f8c419dd205a979ad16ceef87ceeebdee067, actor 1130888, attempt 1. It completed SUCCESS at 11:52:29Z; build job 128395650438 succeeded and deploy job 128395979200 skipped. The controller ended cleanly at 11:52:34.670007Z, and the controller/outer processes are absent.

    The bounded raw log is 336,398 bytes / SHA256 0a32b4ff123d6752fb6b6ff983ab0ffda77cc4897b082da00cae80679d74bd8b. I independently parsed exactly one canonical durable-workflow.php-linux-terminal/v1 object: outcome pass, stage complete, caller product status success, and all seven actual GitHub context fields bind repository durable-workflow/sdk-php, run 42369893733 / attempt 1, workflow_dispatch, refs/heads/main, and both source/workflow SHA to bf40…. Helper/control is ed15002a156725523b23eefb935a243cb1f84952; private-pip/Composer predecessor is 242c2a7fb23459db2e1ada5f84dbee6d61d9b1e5. Receipt v5 / SHA256 3977fd182de8d0eb5ddd091769efc748ee5a238d7511e8911e362db721d8b5ec binds the repository-held 7bc5 installer and the requested PHP 8.3 production / Composer 2.10.3 / PHPUnit 11.5.57 / coverage-none profile. Configuration and normalization revalidate; nine alternatives and 484 private-pip subjects revalidate. Setup cleanup, private-pip cleanup, and the separately identity-bound caller Composer cleanup all pass.

    Both exact provider artifacts reconcile with the run/head and are unexpired:

    • visual artifact 13572922549: 2,807,081 bytes / SHA256 54fc2fcaca87e54d7d835812840cc595efd9a8f75c7e25e606e65598b26da443;
    • Pages artifact 13572354975: 924,047 bytes / SHA256 eaced5f907ce7cc413ec200b0e87ab22ae2d86ef3f46c7594b3378543cd9bc7c.

    I independently downloaded and streamed the Pages wrapper without filesystem extraction or execution. It contains 457 safe TAR members / 421 regular files / 11,843,904 regular-file bytes, with a 716,821-byte maximum member. Its deployment audit is exactly v2 with source, SDK source, and presentation source 6a821568db5c72983bd3990fe27c7990f092db12; published SDK source 11085f0c624674a4b70d3a6fb3e83eaff3869fcb; published version 3.9.4; and workflow revision bf40f8c419dd205a979ad16ceef87ceeebdee067. The index SHA256 is c16aa20b7ab9c749e84840a59d1f730d3a1899959eea444327ecabf6921013ac; it carries the PHP SDK 3.9 / durable-workflow/sdk:^3.9 contract, and the quickstart contract names 3.9.4. I also viewed the bounded prior-source desktop and mobile captures (home-desktop-legacy.png, SHA256 172ceb5fb140649aac0209e09d3a8ff2b8843fa945f8a78fc5d70800021930cd; api-reference-mobile-legacy.png, SHA256 1917d5a11f9c51e3005ba6087be87f6f8eb3b895e6ac71a7769ced57445dafcc); both render coherently and introduce no later presentation donor.

    The first owner artifact audit remains correctly attributed NONPASS: it validated the artifacts and tuple but selected screenshot names from the newer presentation donor, yielding no samples. The read-only successor changed only the two expected prior-source sample names and evidence filename; all provider, archive, size, digest, tuple, and safety predicates stayed intact. Its PASS does not hide or relabel the first observer failure, and no build or dispatch was repeated.

    Nondeployment is proved. Captured provider deployment snapshots before and after are byte-identical; the captured and fresh exact-bf40 Pages deployment queries are empty; the deploy job skipped; the live audit remains the prior schema-v1 / source 6a821… result. Main remains bf40…, tag 3.10.0 remains absent, and the current 46 checks are terminal with 42 successes / four intended skips (three deploy jobs and connected cancellation). The retained evidence root is mode 0700, every evidence file is mode 0600 / single-linked / owner-held, no ZIP or TAR remains there, and no local container/image/network was created by this original.

    This evidence establishes that the maintained protected workflow can rebuild and fully qualify the exact prior-live 3.9.4 tuple while build_only=true prevents deployment. A real rollback remains a distinct future, freshly reviewed and selected full rebuild plus protected deploy using the same 3.9.4 / 6a821… / empty-presentation inputs with build_only=false; no artifact-redeploy shortcut is inferred. Stable 3.9.5 publication, PR350 integration, SDK 3.10, installed/Native/fallback/load, and production rollback decisions remain separate General-owned gates.

  19. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    General accepts the actual prior-live build-only rollback qualification, exact run42369893733/a1 under selection6706550066, based on owner6706622929 and independent 6706641997. Canonical terminal/configuration and setup/private-pip/Composer cleanup, exact3.9.4/11085/6a821/no-presentation/bf40 artifacts, skipped deploy and unchanged current Pages all pass. The first read-only screenshot-name observer NONPASS remains attributed; the fixed bounded observer does not repeat the original.

    The protected prior-live tuple is now qualified for a separately selected full rebuild/terminal/cleanup/deploy rollback route. No actual rollback or new Pages publication is selected by this acceptance. Prepare the complete actual stable3.9.5/a431/bf40 publication proposal, binding the current serving state and this concrete rollback tuple/route/bounds; no artifact-redeploy capability is inferred. Source350/main/tag hold remains until that real effect boundary is settled. Noon backup and General's Cloud operating clocks are independent; SDK owns all publisher observation/cancellation/terminal duties.

  20. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    Prepared, unexecuted stable3.9.5 Pages publication. This is the distinct publication packet requested after the accepted preview, stable build-only and prior-live rollback qualification. It proposes one existing protected workflow_dispatch original, including its normal rebuild and Pages deploy. No dispatch, publication, actual rollback, PR350 merge, source/tag/release/account/secret change is selected by this preparation. Affirmative independent finite review and a later exact fresh General primary selection remain required. SDK-PHP owns the later original, watcher, cancellation, artifact/live audit and cleanup; General's backup/health obligations assume no new observer duty.

    Current accepted prerequisites are General's stable3.9.5 build-only acceptance6705735224, with actual42363142671/a1 and independent6705552920/6705603985; and actual prior-live rollback qualification owner6706622929 / independent terminal/artifact/nondeployment/cleanup PASS6706641997, run42369893733/a1. Both are completed build-only originals. All earlier observer NONPASSs remain attributed, including the last read-only screenshot-name correction; none is relabeled or repeated.

    Subject Exact binding
    Repository / existing workflow durable-workflow/sdk-php /312595210, .github/workflows/docs.yml
    Maintained tooling / tree bf40f8c419dd205a979ad16ceef87ceeebdee067 / 2e5ddc33382696ace11ba14ddc6b670373b517bb
    Workflow blob / SHA256 409e6cf6ab413cceb566a4b4405d9ba4a9fad2cd / 1c61207fda5bfb4c54f7de4bc3ce09ea5f4814368e9350e756f8a552bc1c7c20
    Published SDK tag / Release 3.9.5 /437212955, published/non-draft/non-prerelease
    Published product / tree 57562b53e429a2c3ae1e9aa531ed781e9429bd59 / 6a58907fff58e1a4106514cbb094da4608778fe1
    Presentation donor / tree a4315bcdf62b4a8466c25bd007a9a9d6b06d1f45 / 7ce9a26c7d30f0bb67199b83f615d5fc5667cfc7
    Accepted presentation composition 53files / SHA256 da77db4b72ed27aca60adf0ee3567387013169688478a5b6e2e1d05a21b2fb25
    Helper/control / private-pip+Composer ed15002a156725523b23eefb935a243cb1f84952 / 242c2a7fb23459db2e1ada5f84dbee6d61d9b1e5
    Accepted canonical catalog edba47c8f9d3b9984731bc3fba4e1ab3299f1b9f
    Actual stable quality predecessor 6705735224/bodySHA256 14f2ee0e0af2d43bd8cffd6b78b9807eb3efc2bc2662ed5f504cec3a124d83c4
    Actual rollback owner / acceptance 6706622929/bodySHA256 8f39a44b3e525806f86c52cea9a0aafa59170b8abd2d98eb0714f44e3f1d2f96;6706641997/bodySHA256 fc5503769b1974b134819aae330fb44f15e346f9abd5abeb7fe1d71c37f56417
    Authenticated actor rmcdaniel/id1130888

    The sole proposed original write is one POST to /repos/durable-workflow/sdk-php/actions/workflows/312595210/dispatches, these exact150 canonical bytes / SHA256 a0fe516ea5638cee00d4ab39870adae560322444b32612c90502caea2960e0a3:

    {"ref":"main","inputs":{"stable_tag":"3.9.5","stable_source":"","presentation_source":"a4315bcdf62b4a8466c25bd007a9a9d6b06d1f45","build_only":false}}

    build_only is JSON boolean false. This deliberately enables the existing stable/main deploy gate. Product checkout stays exact3.9.5/57562, presentationa431, toolingGITHUB_WORKFLOW_SHA=bf40. The actual caller context is workflow_dispatch/main/bf40, not the product checkout. Empty stable_source retains the exact published tag. Existing reference admission, path triggers, concurrency group/cancel-in-progress=false, permissions and environment policy remain unchanged. No alternate source, manual artifact restore, tag or publication endpoint is substituted.

    Fresh current state and zero-effect preflight. All46 actual bf40 checks are terminal:42success/four intended skips (three deploy jobs and connected cancellation). Read-only execution of the new adapter's complete source/provider gate passed, as did the exact whole-inventory state and no competing queued/in-progress/waiting publisher. Main isbf40, tag3.10.0 absent. Candidate tag/source/tree/release, donor ancestry, actual rollback annotated tag+peeled product/release/source availability, canonical catalog and workflow identity all match. This preflight executed no dispatch, setup, package request, render, browser or deployment.

    Pages remains workflow-based at https://php.durable-workflow.com/, CNAMEphp.durable-workflow.com, HTTPS enforced. The existing github-pages environment retains only its branch-policy protection selecting main (environment rule59824690/branch policy54542139). Last successful deployment7544896049/status21336102219 is run41822406981/a1. Actual live audit remains118B/SHA256 43c0159fc3ee9317a32e644e20d61d47d2fbf64d23194efe7b8e1f2b86514cd1, schema-v1/source6a821. Admission and immediately-before-dispatch source checks refuse provider, protection, prior-state or source drift. No protection/configuration/credential change is proposed. General and SDK-PHP retain the main/tag3.10 freeze through the independent publication/live audit; any advance requires explicit refresh and new exact qualification.

    Future build and protected deployment graph. The unchanged maintained workflow source owns the complete graph. It checks out the exact product and canonical control without persisted credentials; selects trusted Ubuntu24 system Python; creates fresh held-identity Composer home/cache/scratch; selects private-pip242c for pip/python/composer/curl/git/npm; and runs the accepted literal PHP8.3 production/Composer2.10.3/PHPUnit11.5.57/coverage-none recipe with no added extension/INI inputs. Repository-held installer7bc5, actual archive/runtime/tool/configuration/normalization/loader/CA/alternatives/private-pip subjects require canonical post-product revalidation. This is the already qualified caller/profile path, not a raw profile experiment.

    Maintained toolingbf40 verifies real Composer trust immediately before each actual Composer request. Normal ephemeral hosted acquisition, existing development dependency installation, npm ci --ignore-scripts/audit, examples/navigation/status/asset checks, both unchanged digest-pinned Lychee Docker actions, authored/API rendering, analytics/CNAME checks, accepted no-APT Playwright chromium installation, missing-resource/layout/browser checks, visual upload and exact artifact binding all execute normally. The source-only donor changes presentation over unchanged published SDK bytes. No local build/image acquisition, Server/Cloud/application runtime, paid resource or new account authorization is included.

    The unchanged always wrapper captures caller_product_status before environment closure and blanks loader selectors before absolute system Python. Canonical ed150 qualification must prove pass/complete/productsuccess, configured receipt-v5/repository-held installer, all seven actual GitHub context fields and post-product PHP/tool/configuration/normalization/alternatives/private-pip subjects, then setup and pip cleanup PASS. Independent held-identity Composer cleanup runs in finally, including refusal paths. A failed terminal step fails build and prevents deploy. Pages artifact upload follows successful terminal qualification.

    Then the unchanged deploy job must run on main with stable=true/build_only=false. Only this job grants pages:write/id-token:write and uses the existing github-pages environment. Digest/commit-pinned actions/deploy-pages cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 publishes the same run's Pages artifact. Its unchanged timeout input defaults600000ms; the pinned implementation caps its status-watch timeout at10minutes and cancels pending deployment on timeout/signals. This is the action's bound, not an invented explicit deploy-job timeout. The build job retains its25min native timeout; owner/controller bounds below apply independently. No account, custom domain, protection, DNS or credential mutation is included.

    One-original admission and finite control. This proposal expires 2026-11-07T13:30:00Z. Later General selection must exactly equal the closed object from the Source below, binding this complete packet/independent review body hashes, controller+sealed primitive hashes, exact candidate/predecessor/rollback authority, input/request/source/tree/actor/workflow and all declared limits. The independent review must have an affirmative literal PASS first paragraph. Selection must be<=300s old at admission and immediately before POST. No selection exists or is consumed now. A changed/expired subject requires a fresh packet/review/selection; no automatic reissue or inherited release permission.

    The adapter reuses only exact sealed c69 transport/held-evidence/cancellation Source from 6705135184, SHA256 c69c2dca60196d245b33a735d72dabdc1c918a628f21d4069a3c48043aecc067; its old main is not invoked. The new Source owns admission, the typed publication POST, actual rollback authority, raw build/deploy log capture and new deployment attribution. Request bytes and provider snapshots stay in memory, with exclusive0600/fsynced consumption/evidence under one fresh0700 held-identity root. Pre-existing roots refuse. Existing local gh identity is used with zero vault/configuration/credential changes; raw logs, errors and signed material stay private.

    There is exactly one POST/expectedHTTP204, zero ready/merge/main/tag/release/rollback writes, and at most one exact-original cancel plus one force-cancel. Unknown/non204 acknowledgement consumes the request and stays NONPASS even if attributable deployment later completes; never repeat the dispatch. Discovery binds a unique workflow312595210/eventworkflow_dispatch/main/bf40/actor1130888/attempt1 original in the actual T0 window. Zero/multiple/changed attribution stops without guessing a cancellation target or using a substitute original. Cancellation revalidates that exact run every time.

    Bounds are discovery120s/start allowance300s/watch1200s from T0, normal cancellation90s/force60s, child25s+TERM5s/KILL5s/reaping,4MiB per captured stream,35min outer active+180s termination/cleanup. Signals stop further selected work and reach exact-run cancellation after a handle is bound. The controller returns T0/run handle promptly, captures raw build and deploy logs using the corrected stock raw-control-byte option, and reports uncertainty directly. On terminal capture it compares memory-held before/after provider inventories, requires exactly one new github-pages deployment atbf40 and captures that exact deployment's status records. Its report is TERMINAL_CAPTURED_REQUIRES_AUDIT, never automatic publication acceptance.

    Private diagnostics remain bounded0700/0600 through reconciliation, no later than2026-11-08T12:00Z, then only this original's owned files may be removed. Record actual controller/child termination; do not infer absence from a green job. No local Docker container/image/network is created by the controller. Normal hosted cleanup remains observed workflow evidence; no independent VM-resource absence is invented.

    Required post-effect acceptance. SDK-PHP returns exact primary selection, T0, request hash/HTTP acknowledgement or uncertainty, operation counts, unique run/attempt/context/timestamps and bounds, successful build and deploy, exact deploy-job/deployment/status/URL binding, and strict canonical terminal/configured custody/setup+pip+Composer cleanup. The new status must be successful and its log URL bind this exact run/deploy job, not merely the same maintained SHA. Main checks/source/tag custody must reconcile with the actual added check contexts. Capture provider and bounded raw deploy evidence; failed/unknown/ambiguous outcomes stay NONPASS.

    The read-only artifact audit is limited to the two exact-run Pages/visual artifacts, max32MiB compressed each/64MiB total,256MiB uncompressed,25000 members/16MiB per member,120s active+30s owned cleanup. Verify exact-run/head/provider IDs/sizes/digests, reject unsafe/duplicate/link/device/unsupported members, stream the supported TAR wrapper, execute no archive bytes, and view bounded desktop/mobile samples using the actual selected donor's names. Require v2 audit source_revision/sdk_source_revision/published_sdk_source_revision=57562, presentation_source_revision=a431, workflow_revision=bf40, published_sdk_version3.9.5. UI follows the already qualified3.9/^3.9/quickstart3.9.5 contract. There is no invented patch badge requirement.

    Separately bound the read-only HTTPS live audit to120s active+30s cleanup, maxfive attempts/15s request timeout/1MiB per response. Observe deployment-audit.json and bounded home/quickstart/API pages through the existing URL, validate the same exact v2 tuple and working source-bound links/content/visual samples, and distinguish stale CDN data from provider success. This is observation only; no extra publication/rebuild/refresh request is authorized by a stale response. Missing/expired/unreadable/oversized artifacts, terminal/cleanup gaps, failed deployment, stale live result after bounds, mismatched source or unresolved process state are NONPASS. Report exact provider/live state and the gap to General without retry or automatic rollback. Independent terminal/custody/artifact/live acceptance precedes #315 closure and freeze disposition.

    Qualified executable rollback, not selected. Accepted actual42369893733/a1 proves the existing protected workflow can rebuild prior-live3.9.4 with source6a821/empty presentation onbf40. The actual published tag is annotatedceb70→11085; its admitted source manifest and complete product paths are byte-identical, and acceptance6706641997 binds the full canonical terminal/artifact/cleanup result. The adapter freshly verifies the rollback records and actual tag/product/release/source availability before publication.

    If this later publication needs rollback, the existing executable protected route is a distinct, freshly reviewed and selected full rebuild plus deploy, workflow312595210/refmain on the then-exact qualified harness, inputs stable_tag3.9.4, stable_source6a821568db5c72983bd3990fe27c7990f092db12, presentation_source empty, build_only=false. Its main/check/provider-state admission must be refreshed to the actual post-publication state; the old build-only controller cannot be reused as an effect selection. The full recipe, canonical terminal/dual cleanup, artifacts, Pages environment and native25min build/action10min watch bounds apply, with35min outer active+180s cleanup, exact-original cancellation and independent live audit. It requires registry/network availability and rebuild time; it is not instantaneous restoration. No artifact-redeploy endpoint or automatic retry/fallback is inferred. The rollback authority object in this selection describes readiness/route only and does not select a rollback POST. General owns that separate decision after actual-state capture.

    PR350 and the SDK3.10 cohort remain separate Source/main/tag/installed/Native/fallback/load gates. This publication's success would deliver only the stable3.9.5 documentation tuple and qualified recovery route, not the #328–#332 release or runtime acceptance.

    The complete temporary Source and23 inert controls follow. All API/process/wait behavior is mocked in these tests; they made zero live API mutation, setup/build/deployment call. Tests exercise typed false/one POST, raw build+deploy capture, acknowledged/unknown originals, freshness, source/tag/Pages protection/previous-state drift, rollback authority mutation, wrong/multiple new deployment attribution and exact cancellation. Passing Source tests is not future product/Pages acceptance.

    Publication adapter: 16,040B / SHA256 dac15af35317d052c60557b6f7d16bd20e6599d0fbd402d159a50d2c9401d83b.

    """Finite separately selected stable3.9.5 Pages publication. No source write."""
    import argparse,hashlib,json,os,re,signal,stat,tempfile,types
    from pathlib import Path
    
    BASE_CONTROLLER='c69c2dca60196d245b33a735d72dabdc1c918a628f21d4069a3c48043aecc067'
    base_path=Path(__file__).with_name('preview-once.py')
    base_bytes=base_path.read_bytes()
    if hashlib.sha256(base_bytes).hexdigest()!=BASE_CONTROLLER: raise RuntimeError('Reviewed primitive source changed')
    b=types.ModuleType('held_preview_primitives'); b.__file__=str(base_path)
    exec(compile(base_bytes,str(base_path),'exec'),b.__dict__)
    b.START_BY='2026-11-07T13:30:00+00:00'
    
    MAINTAINED='bf40f8c419dd205a979ad16ceef87ceeebdee067'
    TREE='2e5ddc33382696ace11ba14ddc6b670373b517bb'
    SDK='57562b53e429a2c3ae1e9aa531ed781e9429bd59'
    SDK_TREE='6a58907fff58e1a4106514cbb094da4608778fe1'
    PRESENTATION='a4315bcdf62b4a8466c25bd007a9a9d6b06d1f45'
    PRESENTATION_TREE='7ce9a26c7d30f0bb67199b83f615d5fc5667cfc7'
    PREDECESSOR={'id':6705735224,'body_sha256':'14f2ee0e0af2d43bd8cffd6b78b9807eb3efc2bc2662ed5f504cec3a124d83c4'}
    INPUTS={'stable_tag':'3.9.5','stable_source':'','presentation_source':PRESENTATION,'build_only':False}
    REQUEST=b.encoded({'ref':'main','inputs':INPUTS})
    ROLLBACK={'owner': {'id': 6706622929, 'body_sha256': '8f39a44b3e525806f86c52cea9a0aafa59170b8abd2d98eb0714f44e3f1d2f96'}, 'acceptance': {'id': 6706641997, 'body_sha256': 'fc5503769b1974b134819aae330fb44f15e346f9abd5abeb7fe1d71c37f56417'}, 'qualification_run': 42369893733, 'maintained': 'bf40f8c419dd205a979ad16ceef87ceeebdee067', 'sdk_tag': '3.9.4', 'sdk_tag_object': 'ceb70e243e0bb5237588ddb9abad742ad01dd964', 'sdk_source': '11085f0c624674a4b70d3a6fb3e83eaff3869fcb', 'docs_source': '6a821568db5c72983bd3990fe27c7990f092db12', 'inputs': {'stable_tag': '3.9.4', 'stable_source': '6a821568db5c72983bd3990fe27c7990f092db12', 'presentation_source': '', 'build_only': False}, 'route': 'distinct-freshly-selected-protected-full-rebuild-and-deploy', 'active_seconds': 2100, 'cleanup_seconds': 180}
    LIVE_DEPLOYMENT=7544896049
    LIVE_STATUS=21336102219
    
    def expected(packet,body_hash,review):
        return dict(schema='sdk-php.docs-stable-publication-selection/v1',packet=packet,packet_body_sha256=body_hash,
            review=review,predecessor=PREDECESSOR,rollback_authority=ROLLBACK,controller_sha256=hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),
            primitive_sha256=BASE_CONTROLLER,maintained=MAINTAINED,tree=TREE,central=b.CENTRAL,
            sdk_tag='3.9.5',sdk_source=SDK,sdk_tree=SDK_TREE,presentation=PRESENTATION,presentation_tree=PRESENTATION_TREE,
            inputs=INPUTS,request_sha256=hashlib.sha256(REQUEST).hexdigest(),actor=b.ACTOR,workflow=b.WORKFLOW,
            route='one-manual-stable-pages-publication',start_by=b.START_BY,decision_max_age_seconds=300,
            freeze_main_and_310_tags=True,limits=b.LIMITS)
    
    def comment(identifier):
        row=b.get(f'repos/{b.REPO}/issues/comments/{identifier}')
        if row['user']['id']!=b.ACTOR or not row['issue_url'].endswith('/issues/315'): raise RuntimeError('Primary identity')
        return row
    
    class Original(b.Original):
        def __init__(self,root):
            super().__init__(root); self.merged=MAINTAINED
            self.report['actual_maintained_sha']=MAINTAINED
    
        def subject(self,run):
            return (run['workflow_id']==b.WORKFLOW and run['head_sha']==MAINTAINED and run['head_branch']=='main'
                and run['event']=='workflow_dispatch' and run['actor']['id']==b.ACTOR and run['run_attempt']==1)
    
        def source(self):
            prefix=f'repos/{b.REPO}'
            if b.get(prefix+'/git/ref/heads/main')['object']['sha']!=MAINTAINED: raise RuntimeError('Maintained main changed')
            if b.get(prefix+'/git/commits/'+MAINTAINED)['tree']['sha']!=TREE: raise RuntimeError('Maintained tree changed')
            if b.get('repos/durable-workflow/.github/git/ref/heads/main')['object']['sha']!=b.CENTRAL: raise RuntimeError('Catalog changed')
            tag=b.get(prefix+'/git/ref/tags/3.9.5')['object']
            if tag['type']!='commit' or tag['sha']!=SDK: raise RuntimeError('Published tag changed')
            if b.get(prefix+'/git/commits/'+SDK)['tree']['sha']!=SDK_TREE: raise RuntimeError('Published SDK tree changed')
            release=b.get(prefix+'/releases/tags/3.9.5')
            if (release['id']!=437212955 or release['tag_name']!='3.9.5' or release['target_commitish']!=SDK
                or release['draft'] or release['prerelease'] or not release['published_at']): raise RuntimeError('Published release changed')
            if b.get(prefix+'/git/commits/'+PRESENTATION)['tree']['sha']!=PRESENTATION_TREE: raise RuntimeError('Presentation tree changed')
            ancestry=b.get(prefix+'/compare/'+PRESENTATION+'...'+MAINTAINED)
            if ancestry['status']!='ahead' or ancestry['merge_base_commit']['sha']!=PRESENTATION: raise RuntimeError('Presentation ancestry changed')
            workflow=b.get(prefix+f'/actions/workflows/{b.WORKFLOW}')
            if workflow['id']!=b.WORKFLOW or workflow['path']!='.github/workflows/docs.yml' or workflow['state']!='active': raise RuntimeError('Workflow changed')
            rollback_tag=b.get(prefix+'/git/ref/tags/3.9.4')['object']
            if rollback_tag.get('sha')!=ROLLBACK['sdk_tag_object'] or rollback_tag.get('type')!='tag':
                raise RuntimeError('Rollback tag changed')
            rollback_object=b.get(prefix+'/git/tags/'+ROLLBACK['sdk_tag_object'])['object']
            if rollback_object['sha']!=ROLLBACK['sdk_source'] or rollback_object['type']!='commit': raise RuntimeError('Rollback product changed')
            rollback_release=b.get(prefix+'/releases/tags/3.9.4')
            if rollback_release['id']!=433546777 or rollback_release['draft'] or rollback_release['prerelease'] or not rollback_release['published_at']:
                raise RuntimeError('Rollback release unavailable')
            if b.get(prefix+'/git/commits/'+ROLLBACK['docs_source'])['tree']['sha']!='20409ff5493dd9e2bcc560f14f701393decf1997':
                raise RuntimeError('Rollback documentation source changed')
            pages=b.get(prefix+'/pages')
            if (pages['build_type']!='workflow' or pages['cname']!='php.durable-workflow.com'
                or pages['html_url']!='https://php.durable-workflow.com/' or pages['https_enforced'] is not True
                or pages['source']!={'branch':'main','path':'/'}): raise RuntimeError('Pages configuration changed')
            environment=b.get(prefix+'/environments/github-pages')
            if (environment['name']!='github-pages'
                or environment['deployment_branch_policy']!={'custom_branch_policies':True,'protected_branches':False}
                or [(r['id'],r['type']) for r in environment['protection_rules']]!=[(59824690,'branch_policy')]):
                raise RuntimeError('Pages protection changed')
            policy=b.get(prefix+'/environments/github-pages/deployment-branch-policies')
            if (policy['total_count']!=1 or [(r['id'],r['name'],r['type']) for r in policy['branch_policies']]!=[(54542139,'main','branch')]):
                raise RuntimeError('Pages branch admission changed')
            deployments=b.get(prefix+'/deployments?environment=github-pages&per_page=100')
            if not deployments or deployments[0]['id']!=LIVE_DEPLOYMENT: raise RuntimeError('Prior live deployment changed')
            status=b.get(prefix+f'/deployments/{LIVE_DEPLOYMENT}/statuses')
            if not status or status[0]['id']!=LIVE_STATUS or status[0]['state']!='success': raise RuntimeError('Prior live status changed')
            self.preview_only()
    
        def admit(self,decision_id,packet_id):
            decision=comment(decision_id); selection=json.loads(decision['body']); review=selection.get('review')
            if not isinstance(review,dict) or set(review)!={'id','body_sha256'}: raise RuntimeError('Review shape')
            reviewed=comment(review['id']); packet=comment(packet_id); predecessor=comment(PREDECESSOR['id'])
            if hashlib.sha256(predecessor['body'].encode()).hexdigest()!=PREDECESSOR['body_sha256']: raise RuntimeError('Stable build-only acceptance changed')
            if hashlib.sha256(reviewed['body'].encode()).hexdigest()!=review['body_sha256']: raise RuntimeError('Review changed')
            header=reviewed['body'].split('\n\n',1)[0]
            if '**PASS**' not in header or 'HOLD' in header or 'NONPASS' in header: raise RuntimeError('Affirmative stable effect review required')
            wanted=expected(packet_id,hashlib.sha256(packet['body'].encode()).hexdigest(),review)
            if any(value not in reviewed['body'] for value in (wanted['controller_sha256'],BASE_CONTROLLER,str(packet_id))):
                raise RuntimeError('Stable controller/primitive/packet review binding')
            if selection!=wanted: raise RuntimeError('Closed stable selection differs')
            for key in ('owner','acceptance'):
                authority=comment(ROLLBACK[key]['id'])
                if hashlib.sha256(authority['body'].encode()).hexdigest()!=ROLLBACK[key]['body_sha256']:
                    raise RuntimeError('Rollback authority changed')
                if key=='acceptance' and not authority['body'].startswith('**TERMINAL / ARTIFACT / NONDEPLOYMENT / CLEANUP PASS**'):
                    raise RuntimeError('Rollback qualification not accepted')
            self.fresh(decision)
            if b.get('user')['id']!=b.ACTOR: raise RuntimeError('Actor changed')
            self.source()
            checks=b.get(f'repos/{b.REPO}/commits/{MAINTAINED}/check-runs?per_page=100')['check_runs']
            if (len(checks)!=46 or sum(row['conclusion']=='success' for row in checks)!=42
                or sorted(row['name'] for row in checks if row['conclusion']=='skipped')!=['Connected cooperative cancellation','deploy','deploy','deploy']
                or any(row['status']!='completed' or row['conclusion'] not in ('success','skipped') for row in checks)):
                raise RuntimeError('Maintained qualification changed')
            for status in ('queued','in_progress','waiting'):
                active=b.get(f'repos/{b.REPO}/actions/workflows/{b.WORKFLOW}/runs?status={status}&per_page=100')
                if active['total_count']!=0: raise RuntimeError('Publisher already active')
            self.before_deployments=b.get(f'repos/{b.REPO}/deployments?environment=github-pages&per_page=100')
            self.save('deployments-before.json',self.before_deployments)
            self.save('admission.json',{'decision':decision_id,'selection':selection})
            return decision
    
        def execute(self,decision_id,packet_id):
            decision=self.admit(decision_id,packet_id)
            self.source(); self.fresh(decision)
            self.begun=b.now(); started=b.time.monotonic()
            self.consume('dispatch',REQUEST); self.report['dispatch_posts']=1; acknowledged=False
            self.report['t0']=self.begun.isoformat()
            try:
                response=b.gh('api',f'repos/{b.REPO}/actions/workflows/{b.WORKFLOW}/dispatches','--method','POST','--include','--input','-',input_bytes=REQUEST)
                acknowledged=re.match(rb'HTTP/[0-9.]+ 204(?:\s|$)',response) is not None
                self.report['dispatch_ack']='204' if acknowledged else 'unknown_status'
            except Exception as error: self.report['dispatch_ack']='unknown:'+type(error).__name__
            deadline=b.time.monotonic()+120
            while b.time.monotonic()<deadline:
                rows=b.get(f'repos/{b.REPO}/actions/workflows/{b.WORKFLOW}/runs?event=workflow_dispatch&per_page=100')['workflow_runs']
                matches=[row for row in rows if self.subject(row) and b.stamp(row['created_at'])>=self.begun-b.dt.timedelta(seconds=2)]
                if len(matches)>1: raise RuntimeError('Ambiguous stable discovery; no broad cancellation')
                if matches: self.run_id=matches[0]['id']; break
                b.time.sleep(5)
            if self.run_id is None: raise RuntimeError('No stable original handle; no repeat')
            self.report['run_id']=self.run_id
            self.save('bound-run.json',{'id':self.run_id,'t0':self.begun.isoformat(),'maintained':MAINTAINED})
            observed_started=False
            while b.time.monotonic()-started<1200:
                if self.stop: raise RuntimeError('Stop requested')
                run=b.get(f'repos/{b.REPO}/actions/runs/{self.run_id}')
                if not self.subject(run): raise RuntimeError('Stable subject changed')
                if run['status']=='completed':
                    self.save('run.json',run)
                    jobs=b.get(f'repos/{b.REPO}/actions/runs/{self.run_id}/attempts/1/jobs?per_page=100'); self.save('jobs.json',jobs)
                    self.save('artifacts.json',b.get(f'repos/{b.REPO}/actions/runs/{self.run_id}/artifacts?per_page=100'))
                    after=b.get(f'repos/{b.REPO}/deployments?environment=github-pages&per_page=100')
                    self.save('deployments-after.json',after)
                    self.save('exact-deployments.json',b.get(f'repos/{b.REPO}/deployments?sha={MAINTAINED}&environment=github-pages&per_page=100'))
                    builders=[row for row in jobs['jobs'] if row['name']=='build']
                    deployers=[row for row in jobs['jobs'] if row['name']=='deploy']
                    if len(builders)!=1 or len(deployers)!=1 or jobs['total_count']!=len(jobs['jobs']): raise RuntimeError('Stable terminal capture incomplete')
                    logs=b.gh('api','--allow-escape-sequences',f"repos/{b.REPO}/actions/jobs/{builders[0]['id']}/logs")
                    self.save_bytes('build-raw.log',logs)
                    deploy_logs=b.gh('api','--allow-escape-sequences',f"repos/{b.REPO}/actions/jobs/{deployers[0]['id']}/logs")
                    self.save_bytes('deploy-raw.log',deploy_logs)
                    before=self.before_deployments
                    new=[row for row in after if row['id'] not in {old['id'] for old in before}]
                    if len(new)!=1 or new[0]['sha']!=MAINTAINED or new[0]['environment']!='github-pages':
                        raise RuntimeError('Selected publication deployment attribution differs')
                    deployment=new[0]['id']; self.report['deployment_id']=deployment
                    self.save('deployment-statuses.json',b.get(f'repos/{b.REPO}/deployments/{deployment}/statuses'))
                    self.report.update(deploy_log_sha256=hashlib.sha256(deploy_logs).hexdigest(),deploy_log_bytes=len(deploy_logs))
                    self.report.update(build_log_sha256=hashlib.sha256(logs).hexdigest(),build_log_bytes=len(logs),conclusion=run['conclusion'])
                    if not acknowledged: raise RuntimeError('Dispatch acknowledgement remains uncertain; actual terminal captured')
                    self.report['outcome']='TERMINAL_CAPTURED_REQUIRES_AUDIT'; return
                observed_started=observed_started or run['status']=='in_progress'
                if not observed_started and b.time.monotonic()-started>300: raise RuntimeError('Stable start deadline expired')
                b.time.sleep(15)
            raise RuntimeError('Stable observation deadline expired')
    
    def main():
        parser=argparse.ArgumentParser();parser.add_argument('--decision',type=int,required=True);parser.add_argument('--packet',type=int,required=True)
        args=parser.parse_args()
        if __debug__ is False: raise RuntimeError('Optimized Python not admitted')
        os.umask(0o077);root=Path(tempfile.gettempdir())/('sdk-php-315-publication-'+str(args.packet));root.mkdir(mode=0o700)
        original=Original(root)
        def stop(signum,frame): original.stop=True
        signal.signal(signal.SIGTERM,stop);signal.signal(signal.SIGINT,stop)
        try: original.execute(args.decision,args.packet)
        except BaseException as error: original.report['error']=type(error).__name__+':'+str(error)
        finally:
            try: original.cancel()
            except BaseException as error: original.report['cleanup_error']=type(error).__name__+':'+str(error)
            original.report['ended_at']=b.now().isoformat()
            try: original.save('terminal.json',original.report)
            finally: os.close(original.directory)
        print(json.dumps(original.report,sort_keys=True))
        return 0 if original.report['outcome']=='TERMINAL_CAPTURED_REQUIRES_AUDIT' and 'cleanup_error' not in original.report else 1
    
    if __name__=='__main__': raise SystemExit(main())

    Inert controls: 15,055B / SHA256 1981a9b138c3a50f07fa6117039786777076b4a5eb9b5b4c322c53d838443b5e.

    """Source-only controls: no live API, process, acquisition or publisher call."""
    import datetime as dt,hashlib,importlib.util,json,os,tempfile,unittest
    from pathlib import Path
    from unittest.mock import patch
    
    ROOT=Path(__file__).parent
    spec=importlib.util.spec_from_file_location('stable',ROOT/'publication-once.py');m=importlib.util.module_from_spec(spec);spec.loader.exec_module(m)
    FIXED=dt.datetime(2026,11,7,10,5,tzinfo=dt.timezone.utc)
    
    class Fixture:
        def __init__(self):
            self.writes=[];self.raw_calls=[];self.expired=False;self.unknown=False;self.ambiguous=False
            self.main=m.MAINTAINED;self.sdk=m.SDK;self.draft=False;self.tag=False
            self.tag_object=m.ROLLBACK['sdk_tag_object'];self.dispatched=False;self.new_sha=m.MAINTAINED;self.duplicate_deploy=False;self.page_host='php.durable-workflow.com';self.live_deployment=m.LIVE_DEPLOYMENT;self.live_status='success'
            self.owner='Exact accepted rollback owner.';self.acceptance='**TERMINAL / ARTIFACT / NONDEPLOYMENT / CLEANUP PASS**\n\nAccepted rollback.'
            self.packet='Exact distinct stable packet.';self.predecessor='Accepted prior actual stable build.'
            self.review='**PASS** finite stable effect review\n\n'+hashlib.sha256(Path(m.__file__).read_bytes()).hexdigest()+' '+m.BASE_CONTROLLER+' packet 900'
            self.selection=m.expected(900,hashlib.sha256(self.packet.encode()).hexdigest(),{'id':901,'body_sha256':hashlib.sha256(self.review.encode()).hexdigest()})
            self.checks=[dict(name=str(i),status='completed',conclusion='success') for i in range(42)]
            self.checks.extend([dict(name=name,status='completed',conclusion='skipped') for name in ('Connected cooperative cancellation','deploy','deploy','deploy')])
            self.run=dict(id=987,workflow_id=m.b.WORKFLOW,head_sha=m.MAINTAINED,head_branch='main',event='workflow_dispatch',
                actor={'id':m.b.ACTOR},run_attempt=1,created_at=FIXED.isoformat(),status='completed',conclusion='success')
        def comment(self,body):
            return dict(user={'id':m.b.ACTOR},issue_url=f'https://api.github.com/repos/{m.b.REPO}/issues/315',body=body,
                created_at=(FIXED-dt.timedelta(seconds=301 if self.expired else 1)).isoformat())
        def get(self,path):
            prefix=f'repos/{m.b.REPO}'
            comments={900:self.packet,901:self.review,902:json.dumps(self.selection),m.PREDECESSOR['id']:self.predecessor,
                m.ROLLBACK['owner']['id']:self.owner,m.ROLLBACK['acceptance']['id']:self.acceptance}
            for identifier,body in comments.items():
                if path==prefix+f'/issues/comments/{identifier}': return self.comment(body)
            if path=='user': return {'id':m.b.ACTOR}
            if path=='repos/durable-workflow/.github/git/ref/heads/main': return {'object':{'sha':m.b.CENTRAL}}
            if path==prefix+'/git/ref/heads/main': return {'object':{'sha':self.main}}
            if path==prefix+'/git/ref/tags/3.9.5':return {'object':{'type':'commit','sha':self.sdk}}
            if path==prefix+'/git/ref/tags/3.9.4': return {'object':{'type':'tag','sha':self.tag_object}}
            if path==prefix+'/git/tags/'+m.ROLLBACK['sdk_tag_object']:return {'tag':'3.9.4','object':{'type':'commit','sha':m.ROLLBACK['sdk_source']}}
            for source,tree in ((m.MAINTAINED,m.TREE),(m.SDK,m.SDK_TREE),(m.PRESENTATION,m.PRESENTATION_TREE),(m.ROLLBACK['docs_source'],'20409ff5493dd9e2bcc560f14f701393decf1997')):
                if path==prefix+'/git/commits/'+source:return {'tree':{'sha':tree}}
            if path==prefix+'/releases/tags/3.9.5':return dict(id=437212955,tag_name='3.9.5',target_commitish=m.SDK,draft=self.draft,prerelease=False,published_at=FIXED.isoformat())
            if path==prefix+'/releases/tags/3.9.4': return dict(id=433546777,tag_name='3.9.4',target_commitish='main',draft=False,prerelease=False,published_at=FIXED.isoformat())
            if '/compare/' in path: return {'status':'ahead','merge_base_commit':{'sha':m.PRESENTATION}}
            if path==prefix+f'/actions/workflows/{m.b.WORKFLOW}': return {'id':m.b.WORKFLOW,'path':'.github/workflows/docs.yml','state':'active'}
            if '/git/matching-refs/tags/3.10.0' in path:return [{'ref':'refs/tags/3.10.0'}] if self.tag else []
            if '/check-runs?' in path:return {'check_runs':self.checks}
            if '/runs?status=' in path:return {'total_count':0,'workflow_runs':[]}
            if path==prefix+'/pages':return dict(build_type='workflow',cname=self.page_host,html_url='https://php.durable-workflow.com/',https_enforced=True,source={'branch':'main','path':'/'})
            if path==prefix+'/environments/github-pages':return dict(name='github-pages',deployment_branch_policy={'custom_branch_policies':True,'protected_branches':False},protection_rules=[{'id':59824690,'type':'branch_policy'}])
            if path==prefix+'/environments/github-pages/deployment-branch-policies':return {'total_count':1,'branch_policies':[{'id':54542139,'name':'main','type':'branch'}]}
            if path==prefix+f'/deployments/{m.LIVE_DEPLOYMENT}/statuses':return [{'id':m.LIVE_STATUS,'state':self.live_status}]
            if path==prefix+f'/deployments/{m.LIVE_DEPLOYMENT+1}/statuses':return [{'id':m.LIVE_STATUS+1,'state':'success','log_url':'https://github.com/durable-workflow/sdk-php/actions/runs/987/job/655','environment_url':'https://php.durable-workflow.com/'}]
            if '/deployments?' in path:
                old=[{'id':self.live_deployment}]
                new={'id':m.LIVE_DEPLOYMENT+1,'sha':self.new_sha,'environment':'github-pages'}
                if self.dispatched:return ([new,dict(new,id=new['id']+1)] if self.duplicate_deploy else [new])+old
                return old
            if '/runs?event=workflow_dispatch' in path:return {'workflow_runs':[self.run]*(2 if self.ambiguous else 1)}
            if path==prefix+'/actions/runs/987':return self.run
            if '/attempts/1/jobs?' in path:return {'total_count':2,'jobs':[{'id':654,'name':'build'},{'id':655,'name':'deploy'}]}
            if '/artifacts?' in path:return {'total_count':2,'artifacts':[]}
            raise AssertionError('Unexpected read '+path)
        def gh(self,*arguments,input_bytes=None):
            if '--method' not in arguments:
                self.raw_calls.append(arguments)
                if '--allow-escape-sequences' not in arguments: raise AssertionError('Raw-log opt-in absent')
                return b'\x1b[32mprivate mocked raw log\n'
            self.writes.append((arguments,input_bytes));self.dispatched=True
            if not arguments[1].endswith('/dispatches'): raise AssertionError('Unexpected protected mutation')
            if self.unknown: raise RuntimeError('unknown acknowledgement')
            return b'HTTP/2.0 204 No Content\r\n\r\n'
    
    class Controls(unittest.TestCase):
        def setUp(self):
            self.temp=tempfile.TemporaryDirectory(prefix='sdk-php-stable-inert-');self.root=Path(self.temp.name);self.root.chmod(0o700)
            self.original=m.Original(self.root)
            self.predecessor=patch.dict(m.PREDECESSOR,{'body_sha256':hashlib.sha256(b'Accepted prior actual stable build.').hexdigest()});self.predecessor.start()
            self.rollback=patch.dict(m.ROLLBACK,{
                'owner':{'id':6706622929,'body_sha256':hashlib.sha256(b'Exact accepted rollback owner.').hexdigest()},
                'acceptance':{'id':6706641997,'body_sha256':hashlib.sha256(b'**TERMINAL / ARTIFACT / NONDEPLOYMENT / CLEANUP PASS**\n\nAccepted rollback.').hexdigest()}});self.rollback.start()
            self.fixture=Fixture()
            self.patches=[patch.object(m.b,'get',self.fixture.get),patch.object(m.b,'gh',self.fixture.gh),patch.object(m.b,'now',lambda:FIXED),patch.object(m.b.time,'sleep',lambda seconds:None)]
            for item in self.patches:item.start()
        def tearDown(self):
            for item in reversed(self.patches):item.stop()
            self.rollback.stop();self.predecessor.stop();os.close(self.original.directory);self.temp.cleanup()
        def execute(self):self.original.execute(902,900)
        def test_exact_one_typed_publication_and_raw_build_deploy_capture(self):
            self.execute()
            self.assertEqual(len(self.fixture.writes),1)
            request=json.loads(self.fixture.writes[0][1]);self.assertIs(request['inputs']['build_only'],False)
            self.assertEqual(request,{'ref':'main','inputs':m.INPUTS})
            self.assertEqual(request['inputs']['stable_tag'],'3.9.5')
            self.assertEqual(request['inputs']['stable_source'],'')
            self.assertEqual(request['inputs']['presentation_source'],m.PRESENTATION)
            self.assertEqual(self.original.report['dispatch_ack'],'204')
            self.assertEqual(self.original.report['outcome'],'TERMINAL_CAPTURED_REQUIRES_AUDIT')
            self.assertEqual((self.original.report['ready_posts'],self.original.report['merge_puts']),(0,0))
            self.assertTrue(all('--allow-escape-sequences' in x for x in self.fixture.raw_calls));self.assertEqual(len(self.fixture.raw_calls),2)
            self.assertEqual(self.original.report['deployment_id'],m.LIVE_DEPLOYMENT+1)
        def test_unknown_dispatch_ack_is_consumed_once_and_observed_without_retry(self):
            self.fixture.unknown=True
            with self.assertRaisesRegex(RuntimeError,'acknowledgement remains uncertain'):self.execute()
            self.assertEqual(len(self.fixture.writes),1);self.assertTrue((self.root/'run.json').exists())
            self.assertEqual(self.original.report['outcome'],'NONPASS')
        def test_stale_selection_zero_writes(self):
            self.fixture.expired=True
            with self.assertRaisesRegex(RuntimeError,'expired'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_main_zero_writes(self):
            self.fixture.main='b'*40
            with self.assertRaisesRegex(RuntimeError,'main changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_published_tag_zero_writes(self):
            self.fixture.sdk='b'*40
            with self.assertRaisesRegex(RuntimeError,'Published tag changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_unpublished_release_zero_writes(self):
            self.fixture.draft=True
            with self.assertRaisesRegex(RuntimeError,'release changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_preview_acceptance_zero_writes(self):
            self.fixture.predecessor+=' changed'
            with self.assertRaisesRegex(RuntimeError,'Stable build-only acceptance changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_build_only_true_in_publication_selection_zero_writes(self):
            self.fixture.selection['inputs']=dict(m.INPUTS,build_only=True)
            with self.assertRaisesRegex(RuntimeError,'selection differs'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_present_310_tag_zero_writes(self):
            self.fixture.tag=True
            with self.assertRaisesRegex(RuntimeError,'tag is no longer absent'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_checks_zero_writes(self):
            self.fixture.checks[0]['conclusion']='failure'
            with self.assertRaisesRegex(RuntimeError,'qualification changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_ambiguous_run_has_no_repeat_or_broad_cancel(self):
            self.fixture.ambiguous=True
            with self.assertRaisesRegex(RuntimeError,'Ambiguous stable'):self.execute()
            self.original.cancel();self.assertEqual(len(self.fixture.writes),1)
        def test_changed_cancellation_subject_has_no_mutation(self):
            self.original.run_id=987;self.fixture.run['head_sha']='b'*40
            with self.assertRaisesRegex(RuntimeError,'subject changed'):self.original.cancel()
            self.assertEqual(self.fixture.writes,[])
        def test_unreviewed_primitive_bytes_refuse_before_import(self):
            with tempfile.TemporaryDirectory(prefix='sdk-php-primitive-negative-') as directory:
                copy=Path(directory)/'publication-once.py';copy.write_bytes(Path(m.__file__).read_bytes())
                copy.with_name('preview-once.py').write_text('raise AssertionError("unreviewed execution")\n')
                spec=importlib.util.spec_from_file_location('refused_rollback',copy);module=importlib.util.module_from_spec(spec)
                with self.assertRaisesRegex(RuntimeError,'primitive source changed'):spec.loader.exec_module(module)
    
        def test_changed_annotated_tag_object_zero_writes(self):
            self.fixture.tag_object='b'*40
            with self.assertRaisesRegex(RuntimeError,'Rollback tag changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_presentation_donor_in_selection_zero_writes(self):
            self.fixture.selection['inputs']=dict(m.INPUTS,presentation_source='a'*40)
            with self.assertRaisesRegex(RuntimeError,'selection differs'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_pages_host_zero_writes(self):
            self.fixture.page_host='other.example.test'
            with self.assertRaisesRegex(RuntimeError,'Pages configuration changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_live_deployment_zero_writes(self):
            self.fixture.live_deployment+=1
            with self.assertRaisesRegex(RuntimeError,'Prior live deployment changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_failed_live_status_zero_writes(self):
            self.fixture.live_status='failure'
            with self.assertRaisesRegex(RuntimeError,'Prior live status changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_protected_branch_policy_zero_writes(self):
            old=self.fixture.get
            def get(path):
                row=old(path)
                if path.endswith('/deployment-branch-policies'):row['branch_policies'][0]['name']='other'
                return row
            with patch.object(m.b,'get',get):
                with self.assertRaisesRegex(RuntimeError,'Pages branch admission changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
    
        def test_changed_rollback_owner_refuses_before_write(self):
            self.fixture.owner+=' changed'
            with self.assertRaisesRegex(RuntimeError,'Rollback authority changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_rollback_acceptance_refuses_before_write(self):
            self.fixture.acceptance+=' changed'
            with self.assertRaisesRegex(RuntimeError,'Rollback authority changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_wrong_new_deployment_head_is_consumed_not_repeated(self):
            self.fixture.new_sha='b'*40
            with self.assertRaisesRegex(RuntimeError,'deployment attribution differs'):self.execute()
            self.assertEqual(len(self.fixture.writes),1)
        def test_multiple_new_deployments_refuse_without_repeat(self):
            self.fixture.duplicate_deploy=True
            with self.assertRaisesRegex(RuntimeError,'deployment attribution differs'):self.execute()
            self.assertEqual(len(self.fixture.writes),1)
    
    if __name__=='__main__':unittest.main()
  21. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    HOLD — exact publication packet 6706719643 / body SHA-256 f2dc013032cf646b0a41e80046047dea5edabc6739dc7dce92099deb3f99629e is not admitted. The proposed adapter is dac15af35317d052c60557b6f7d16bd20e6599d0fbd402d159a50d2c9401d83b over sealed primitive c69c2dca60196d245b33a735d72dabdc1c918a628f21d4069a3c48043aecc067. I ran only the supplied mocked fixture plus local pathname-replacement controls: zero live API mutation, dispatch, build, deployment, setup, package, or rollback effect.

    Three fail-closed gaps remain before this high-impact build_only=false publication can be selected:

    1. The review does not bind the exact packet body. admit() recomputes the current packet hash for selection, but its review-text check requires only controller SHA, primitive SHA, and packet ID. An edited packet plus a fresh selection therefore passes against the unchanged old review. Causal control: replace the fixture packet after review, recompute the closed selection for the edited body, leave the review byte-identical; execute() returned and issued the one mocked POST. Require the exact packet_body_sha256 in the independently reviewed body and verify that value explicitly before any write.

    2. The last freshness/stop and competing-publisher gates are before the consumption record, not immediately before POST. execute() calls source(); fresh(); consume(); POST. Causal control: set original.stop=True from the mocked consume("dispatch", ...); the POST was still issued, and only the later observation loop raised Stop requested. A second control made a publisher active immediately after admit(); the later source() does not recheck queued/in-progress/waiting publisher state, so the POST still issued. Recheck stop/decision age/start-by and all three competing-publisher statuses after the durable local consumption record and immediately before the provider write; also retain the exact source/provider state required by the packet at that boundary.

    3. The selected controller hash can identify pathname replacement bytes rather than the executing adapter. expected() hashes Path(__file__).read_bytes() after import. Causal control: import the exact dac15af3… adapter, replace only its pathname, then call expected(); controller_sha256 became the replacement SHA ffa4bfd8317a69e181debd2c224a177cc23fa64c660fbdaa837ea47f9401b249, not the executing dac15af3… bytes. Hold/execute the adapter through one sealed regular-file descriptor (or an equivalently reviewed loader that compiles the held bytes) and derive the selected hash from those same executing bytes; do not reopen a mutable pathname for authority.

    The typed 150-byte request, exact SDK/presentation/main identities, bound stable build and rollback qualifications, Pages protection, one-original discovery/cancellation structure, raw build/deploy capture, and post-effect audit scope otherwise remain coherent within this review. Preserve the current packet and all prior build-only/rollback results as historical; return a changed exact controller/packet with causal controls for the three closures. This HOLD selects no publication or rollback and does not weaken the main/tag freeze.

  22. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    Changed successor for the unexecuted publication HOLD. Original packet 6706719643, controllerdac15 and HOLD6706754233 remain preserved. No publication was selected or launched. This successor closes the three causal Source gaps with a changed adapter, held-bytes entrypoint and32 inert controls; it requires a new exact independent review and fresh General selection. The typed request, product/presentation/rollback identities, workflow/deployment graph, current46-check/provider subject, audit requirements and finite bounds remain the same. No historical build/rollback result is relabeled.

    The edited-packet, stop-after-consumption, newly-active-publisher-after-admission and pathname-replacement causal controls all fail against the preserveddac15 predecessor and pass on this successor. All32 candidate controls pass. They perform no live API mutation, setup, package, build or deploy; API/wait calls are mocked, and the loader controls execute only owned temporary standard-library fixture bytes.

    Prepared, unexecuted stable3.9.5 Pages publication. This is the distinct publication packet requested after the accepted preview, stable build-only and prior-live rollback qualification. It proposes one existing protected workflow_dispatch original, including its normal rebuild and Pages deploy. No dispatch, publication, actual rollback, PR350 merge, source/tag/release/account/secret change is selected by this preparation. Affirmative independent finite review and a later exact fresh General primary selection remain required. SDK-PHP owns the later original, watcher, cancellation, artifact/live audit and cleanup; General's backup/health obligations assume no new observer duty.

    Current accepted prerequisites are General's stable3.9.5 build-only acceptance6705735224, with actual42363142671/a1 and independent6705552920/6705603985; and actual prior-live rollback qualification owner6706622929 / independent terminal/artifact/nondeployment/cleanup PASS6706641997, run42369893733/a1. Both are completed build-only originals. All earlier observer NONPASSs remain attributed, including the last read-only screenshot-name correction; none is relabeled or repeated.

    Subject Exact binding
    Repository / existing workflow durable-workflow/sdk-php /312595210, .github/workflows/docs.yml
    Maintained tooling / tree bf40f8c419dd205a979ad16ceef87ceeebdee067 / 2e5ddc33382696ace11ba14ddc6b670373b517bb
    Workflow blob / SHA256 409e6cf6ab413cceb566a4b4405d9ba4a9fad2cd / 1c61207fda5bfb4c54f7de4bc3ce09ea5f4814368e9350e756f8a552bc1c7c20
    Published SDK tag / Release 3.9.5 /437212955, published/non-draft/non-prerelease
    Published product / tree 57562b53e429a2c3ae1e9aa531ed781e9429bd59 / 6a58907fff58e1a4106514cbb094da4608778fe1
    Presentation donor / tree a4315bcdf62b4a8466c25bd007a9a9d6b06d1f45 / 7ce9a26c7d30f0bb67199b83f615d5fc5667cfc7
    Accepted presentation composition 53files / SHA256 da77db4b72ed27aca60adf0ee3567387013169688478a5b6e2e1d05a21b2fb25
    Helper/control / private-pip+Composer ed15002a156725523b23eefb935a243cb1f84952 / 242c2a7fb23459db2e1ada5f84dbee6d61d9b1e5
    Accepted canonical catalog edba47c8f9d3b9984731bc3fba4e1ab3299f1b9f
    Actual stable quality predecessor 6705735224/bodySHA256 14f2ee0e0af2d43bd8cffd6b78b9807eb3efc2bc2662ed5f504cec3a124d83c4
    Actual rollback owner / acceptance 6706622929/bodySHA256 8f39a44b3e525806f86c52cea9a0aafa59170b8abd2d98eb0714f44e3f1d2f96;6706641997/bodySHA256 fc5503769b1974b134819aae330fb44f15e346f9abd5abeb7fe1d71c37f56417
    Authenticated actor rmcdaniel/id1130888

    The sole proposed original write is one POST to /repos/durable-workflow/sdk-php/actions/workflows/312595210/dispatches, these exact150 canonical bytes / SHA256 a0fe516ea5638cee00d4ab39870adae560322444b32612c90502caea2960e0a3:

    {"ref":"main","inputs":{"stable_tag":"3.9.5","stable_source":"","presentation_source":"a4315bcdf62b4a8466c25bd007a9a9d6b06d1f45","build_only":false}}

    build_only is JSON boolean false. This deliberately enables the existing stable/main deploy gate. Product checkout stays exact3.9.5/57562, presentationa431, toolingGITHUB_WORKFLOW_SHA=bf40. The actual caller context is workflow_dispatch/main/bf40, not the product checkout. Empty stable_source retains the exact published tag. Existing reference admission, path triggers, concurrency group/cancel-in-progress=false, permissions and environment policy remain unchanged. No alternate source, manual artifact restore, tag or publication endpoint is substituted.

    Fresh current state and zero-effect preflight. All46 actual bf40 checks are terminal:42success/four intended skips (three deploy jobs and connected cancellation). Read-only execution of the new adapter's complete source/provider gate passed, as did the exact whole-inventory state and no competing queued/in-progress/waiting publisher. Main isbf40, tag3.10.0 absent. Candidate tag/source/tree/release, donor ancestry, actual rollback annotated tag+peeled product/release/source availability, canonical catalog and workflow identity all match. This preflight executed no dispatch, setup, package request, render, browser or deployment.

    Pages remains workflow-based at https://php.durable-workflow.com/, CNAMEphp.durable-workflow.com, HTTPS enforced. The existing github-pages environment retains only its branch-policy protection selecting main (environment rule59824690/branch policy54542139). Last successful deployment7544896049/status21336102219 is run41822406981/a1. Actual live audit remains118B/SHA256 43c0159fc3ee9317a32e644e20d61d47d2fbf64d23194efe7b8e1f2b86514cd1, schema-v1/source6a821. Admission and immediately-before-dispatch source checks refuse provider, protection, prior-state or source drift. No protection/configuration/credential change is proposed. General and SDK-PHP retain the main/tag3.10 freeze through the independent publication/live audit; any advance requires explicit refresh and new exact qualification.

    Future build and protected deployment graph. The unchanged maintained workflow source owns the complete graph. It checks out the exact product and canonical control without persisted credentials; selects trusted Ubuntu24 system Python; creates fresh held-identity Composer home/cache/scratch; selects private-pip242c for pip/python/composer/curl/git/npm; and runs the accepted literal PHP8.3 production/Composer2.10.3/PHPUnit11.5.57/coverage-none recipe with no added extension/INI inputs. Repository-held installer7bc5, actual archive/runtime/tool/configuration/normalization/loader/CA/alternatives/private-pip subjects require canonical post-product revalidation. This is the already qualified caller/profile path, not a raw profile experiment.

    Maintained toolingbf40 verifies real Composer trust immediately before each actual Composer request. Normal ephemeral hosted acquisition, existing development dependency installation, npm ci --ignore-scripts/audit, examples/navigation/status/asset checks, both unchanged digest-pinned Lychee Docker actions, authored/API rendering, analytics/CNAME checks, accepted no-APT Playwright chromium installation, missing-resource/layout/browser checks, visual upload and exact artifact binding all execute normally. The source-only donor changes presentation over unchanged published SDK bytes. No local build/image acquisition, Server/Cloud/application runtime, paid resource or new account authorization is included.

    The unchanged always wrapper captures caller_product_status before environment closure and blanks loader selectors before absolute system Python. Canonical ed150 qualification must prove pass/complete/productsuccess, configured receipt-v5/repository-held installer, all seven actual GitHub context fields and post-product PHP/tool/configuration/normalization/alternatives/private-pip subjects, then setup and pip cleanup PASS. Independent held-identity Composer cleanup runs in finally, including refusal paths. A failed terminal step fails build and prevents deploy. Pages artifact upload follows successful terminal qualification.

    Then the unchanged deploy job must run on main with stable=true/build_only=false. Only this job grants pages:write/id-token:write and uses the existing github-pages environment. Digest/commit-pinned actions/deploy-pages cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 publishes the same run's Pages artifact. Its unchanged timeout input defaults600000ms; the pinned implementation caps its status-watch timeout at10minutes and cancels pending deployment on timeout/signals. This is the action's bound, not an invented explicit deploy-job timeout. The build job retains its25min native timeout; owner/controller bounds below apply independently. No account, custom domain, protection, DNS or credential mutation is included.

    One-original admission and finite control. This proposal expires 2026-11-07T13:30:00Z. Later General selection must exactly equal the closed object from the Source below, binding this complete packet/independent review body hashes, controller+sealed primitive+literal loader hashes, exact candidate/predecessor/rollback authority, input/request/source/tree/actor/workflow and all declared limits. The independent review first paragraph must have affirmative literal PASS and explicitly include the exact packet ID/body SHA256, executing adapter SHA256, sealed primitive SHA256 and literal loader SHA256. admit() verifies every value in that paragraph, not merely the current selection or an unrelated quoted body. Selection must be<=300s old at admission and immediately before POST. No selection exists or is consumed now. A changed/expired subject requires a fresh packet/review/selection; no automatic reissue or inherited release permission.

    The adapter reuses only exact sealed c69 transport/held-evidence/cancellation Source from 6705135184, SHA256 c69c2dca60196d245b33a735d72dabdc1c918a628f21d4069a3c48043aecc067; its old main is not invoked. The new Source owns admission, the typed publication POST, actual rollback authority, raw build/deploy log capture and new deployment attribution. Its closed schema is sdk-php.docs-stable-publication-selection/v2. After durable request consumption it immediately rechecks stop/decision age/start-by, exact source/provider state and all three competing-publisher statuses, then repeats freshness immediately before the provider call. A signal or competing publisher observed there gives zero POSTs; consumption is reported separately and the original is not retried. T0 and dispatch_posts are set only after these gates at the actual call boundary. Once the provider call begins, uncertainty remains consumed and is reconciled without retry. Request bytes and provider snapshots stay in memory, with exclusive0600/fsynced consumption/evidence under one fresh0700 held-identity root. Pre-existing roots refuse. Existing local gh identity is used with zero vault/configuration/credential changes; raw logs, errors and signed material stay private.

    There is exactly one POST/expectedHTTP204, zero ready/merge/main/tag/release/rollback writes, and at most one exact-original cancel plus one force-cancel. Unknown/non204 acknowledgement consumes the request and stays NONPASS even if attributable deployment later completes; never repeat the dispatch. Discovery binds a unique workflow312595210/eventworkflow_dispatch/main/bf40/actor1130888/attempt1 original in the actual T0 window. Zero/multiple/changed attribution stops without guessing a cancellation target or using a substitute original. Cancellation revalidates that exact run every time.

    Bounds are discovery120s/start allowance300s/watch1200s from T0, normal cancellation90s/force60s, child25s+TERM5s/KILL5s/reaping,4MiB per captured stream,35min outer active+180s termination/cleanup. Signals stop further selected work and reach exact-run cancellation after a handle is bound. The controller returns T0/run handle promptly, captures raw build and deploy logs using the corrected stock raw-control-byte option, and reports uncertainty directly. On terminal capture it compares memory-held before/after provider inventories, requires exactly one new github-pages deployment atbf40 and captures that exact deployment's status records. Its report is TERMINAL_CAPTURED_REQUIRES_AUDIT, never automatic publication acceptance.

    Private diagnostics remain bounded0700/0600 through reconciliation, no later than2026-11-08T12:00Z, then only this original's owned files may be removed. Record actual controller/child termination; do not infer absence from a green job. No local Docker container/image/network is created by the controller. Normal hosted cleanup remains observed workflow evidence; no independent VM-resource absence is invented.

    Required post-effect acceptance. SDK-PHP returns exact primary selection, T0, request hash/HTTP acknowledgement or uncertainty, operation counts, unique run/attempt/context/timestamps and bounds, successful build and deploy, exact deploy-job/deployment/status/URL binding, and strict canonical terminal/configured custody/setup+pip+Composer cleanup. The new status must be successful and its log URL bind this exact run/deploy job, not merely the same maintained SHA. Main checks/source/tag custody must reconcile with the actual added check contexts. Capture provider and bounded raw deploy evidence; failed/unknown/ambiguous outcomes stay NONPASS.

    The read-only artifact audit is limited to the two exact-run Pages/visual artifacts, max32MiB compressed each/64MiB total,256MiB uncompressed,25000 members/16MiB per member,120s active+30s owned cleanup. Verify exact-run/head/provider IDs/sizes/digests, reject unsafe/duplicate/link/device/unsupported members, stream the supported TAR wrapper, execute no archive bytes, and view bounded desktop/mobile samples using the actual selected donor's names. Require v2 audit source_revision/sdk_source_revision/published_sdk_source_revision=57562, presentation_source_revision=a431, workflow_revision=bf40, published_sdk_version3.9.5. UI follows the already qualified3.9/^3.9/quickstart3.9.5 contract. There is no invented patch badge requirement.

    Separately bound the read-only HTTPS live audit to120s active+30s cleanup, maxfive attempts/15s request timeout/1MiB per response. Observe deployment-audit.json and bounded home/quickstart/API pages through the existing URL, validate the same exact v2 tuple and working source-bound links/content/visual samples, and distinguish stale CDN data from provider success. This is observation only; no extra publication/rebuild/refresh request is authorized by a stale response. Missing/expired/unreadable/oversized artifacts, terminal/cleanup gaps, failed deployment, stale live result after bounds, mismatched source or unresolved process state are NONPASS. Report exact provider/live state and the gap to General without retry or automatic rollback. Independent terminal/custody/artifact/live acceptance precedes #315 closure and freeze disposition.

    Qualified executable rollback, not selected. Accepted actual42369893733/a1 proves the existing protected workflow can rebuild prior-live3.9.4 with source6a821/empty presentation onbf40. The actual published tag is annotatedceb70→11085; its admitted source manifest and complete product paths are byte-identical, and acceptance6706641997 binds the full canonical terminal/artifact/cleanup result. The adapter freshly verifies the rollback records and actual tag/product/release/source availability before publication.

    If this later publication needs rollback, the existing executable protected route is a distinct, freshly reviewed and selected full rebuild plus deploy, workflow312595210/refmain on the then-exact qualified harness, inputs stable_tag3.9.4, stable_source6a821568db5c72983bd3990fe27c7990f092db12, presentation_source empty, build_only=false. Its main/check/provider-state admission must be refreshed to the actual post-publication state; the old build-only controller cannot be reused as an effect selection. The full recipe, canonical terminal/dual cleanup, artifacts, Pages environment and native25min build/action10min watch bounds apply, with35min outer active+180s cleanup, exact-original cancellation and independent live audit. It requires registry/network availability and rebuild time; it is not instantaneous restoration. No artifact-redeploy endpoint or automatic retry/fallback is inferred. The rollback authority object in this selection describes readiness/route only and does not select a rollback POST. General owns that separate decision after actual-state capture.

    PR350 and the SDK3.10 cohort remain separate Source/main/tag/installed/Native/fallback/load gates. This publication's success would deliver only the stable3.9.5 documentation tuple and qualified recovery route, not the #328–#332 release or runtime acceptance.

    The complete temporary Source, literal held-bytes entrypoint and32 inert controls follow. All API/wait behavior is mocked; the owned-file loader fixture controls execute no process or network operation. These tests made zero live API mutation, setup/build/deployment call. Tests exercise typed false/one POST, raw build+deploy capture, acknowledged/unknown originals, freshness, source/tag/Pages protection/previous-state drift, rollback authority mutation, wrong/multiple new deployment attribution and exact cancellation. The four predecessor-fail/candidate-pass causal controls close the exact HOLD; additional loader controls reject missing custody, wrong digest and group/world-writable Source. Passing Source tests is not future product/Pages acceptance.

    Held executing-source custody is mandatory. Direct pathname execution is refused by the adapter. The actual outer command must pass the following literal reviewed loader Source to isolated system Python (python3 -I -B -c <literal> <controller-file> <exact-reviewed-controller-sha> --decision <primary-id> --packet <this-packet-id>), under the same35min+180s outer bound. SDK-PHP verifies the literal string's SHA256 against the selected loader hash before use. Do not execute a mutable loader pathname or substitute python3 controller.py.

    The literal opens one no-follow regular-file descriptor, checks owner/single-link/non-writable-to-group-or-world/size and stable descriptor metadata, reads at most65537 bytes, verifies the exact selected adapter SHA, then compiles and executes those same immutable held bytes with their byte object injected. The adapter derives its authority hash only from that executing byte object, never by reopening file. The held c69 primitive is independently hashed before compile as before. A pathname replacement cannot change the selected controller identity or the executing bytes. The isolated interpreter and literal entrypoint are the trusted invocation boundary; the closed selection also binds the loader's exact hash.

    Literal entrypoint: 882B / SHA256 e0bba095c27166d967986e97f6fad0b7e3407f409c95cc980cd017755bff3614.

    import hashlib,os,stat,sys
    path,digest=sys.argv[1:3]
    fd=os.open(path,os.O_RDONLY|os.O_CLOEXEC|os.O_NOFOLLOW)
    try:
        initial=os.fstat(fd)
        if not stat.S_ISREG(initial.st_mode) or initial.st_uid!=os.getuid() or initial.st_nlink!=1 or initial.st_mode&0o022 or not 0<initial.st_size<=65536:
            raise RuntimeError('Controller file authority refused')
        held=os.read(fd,65537)
        final=os.fstat(fd)
        fields=('st_dev','st_ino','st_uid','st_mode','st_nlink','st_size','st_mtime_ns','st_ctime_ns')
        if len(held)!=initial.st_size or any(getattr(initial,k)!=getattr(final,k) for k in fields) or hashlib.sha256(held).hexdigest()!=digest:
            raise RuntimeError('Controller held bytes differ from selected Source')
    finally:
        os.close(fd)
    sys.argv=[path,*sys.argv[3:]]
    exec(compile(held,path,'exec'),{'__name__':'__main__','__file__':path,'__held_source_bytes__':held})

    Changed publication adapter: 16,934B / SHA256 217d696b87dbffbc5796be0f4ca2293edbfa5bad330282cf1525bba8972a206d.

    """Finite separately selected stable3.9.5 Pages publication. No source write."""
    import argparse,hashlib,json,os,re,signal,stat,tempfile,types
    from pathlib import Path
    
    _HELD_EXECUTING_SOURCE=globals().pop('__held_source_bytes__',None)
    if not isinstance(_HELD_EXECUTING_SOURCE,bytes) or not 0<len(_HELD_EXECUTING_SOURCE)<=65536:
        raise RuntimeError('Execute only through the reviewed held-bytes loader')
    EXECUTING_SOURCE_SHA256=hashlib.sha256(_HELD_EXECUTING_SOURCE).hexdigest()
    HELD_LOADER_SHA256='e0bba095c27166d967986e97f6fad0b7e3407f409c95cc980cd017755bff3614'
    
    BASE_CONTROLLER='c69c2dca60196d245b33a735d72dabdc1c918a628f21d4069a3c48043aecc067'
    base_path=Path(__file__).with_name('preview-once.py')
    base_bytes=base_path.read_bytes()
    if hashlib.sha256(base_bytes).hexdigest()!=BASE_CONTROLLER: raise RuntimeError('Reviewed primitive source changed')
    b=types.ModuleType('held_preview_primitives'); b.__file__=str(base_path)
    exec(compile(base_bytes,str(base_path),'exec'),b.__dict__)
    b.START_BY='2026-11-07T13:30:00+00:00'
    
    MAINTAINED='bf40f8c419dd205a979ad16ceef87ceeebdee067'
    TREE='2e5ddc33382696ace11ba14ddc6b670373b517bb'
    SDK='57562b53e429a2c3ae1e9aa531ed781e9429bd59'
    SDK_TREE='6a58907fff58e1a4106514cbb094da4608778fe1'
    PRESENTATION='a4315bcdf62b4a8466c25bd007a9a9d6b06d1f45'
    PRESENTATION_TREE='7ce9a26c7d30f0bb67199b83f615d5fc5667cfc7'
    PREDECESSOR={'id':6705735224,'body_sha256':'14f2ee0e0af2d43bd8cffd6b78b9807eb3efc2bc2662ed5f504cec3a124d83c4'}
    INPUTS={'stable_tag':'3.9.5','stable_source':'','presentation_source':PRESENTATION,'build_only':False}
    REQUEST=b.encoded({'ref':'main','inputs':INPUTS})
    ROLLBACK={'owner': {'id': 6706622929, 'body_sha256': '8f39a44b3e525806f86c52cea9a0aafa59170b8abd2d98eb0714f44e3f1d2f96'}, 'acceptance': {'id': 6706641997, 'body_sha256': 'fc5503769b1974b134819aae330fb44f15e346f9abd5abeb7fe1d71c37f56417'}, 'qualification_run': 42369893733, 'maintained': 'bf40f8c419dd205a979ad16ceef87ceeebdee067', 'sdk_tag': '3.9.4', 'sdk_tag_object': 'ceb70e243e0bb5237588ddb9abad742ad01dd964', 'sdk_source': '11085f0c624674a4b70d3a6fb3e83eaff3869fcb', 'docs_source': '6a821568db5c72983bd3990fe27c7990f092db12', 'inputs': {'stable_tag': '3.9.4', 'stable_source': '6a821568db5c72983bd3990fe27c7990f092db12', 'presentation_source': '', 'build_only': False}, 'route': 'distinct-freshly-selected-protected-full-rebuild-and-deploy', 'active_seconds': 2100, 'cleanup_seconds': 180}
    LIVE_DEPLOYMENT=7544896049
    LIVE_STATUS=21336102219
    
    def expected(packet,body_hash,review):
        return dict(schema='sdk-php.docs-stable-publication-selection/v2',packet=packet,packet_body_sha256=body_hash,
            review=review,predecessor=PREDECESSOR,rollback_authority=ROLLBACK,controller_sha256=EXECUTING_SOURCE_SHA256,
            primitive_sha256=BASE_CONTROLLER,loader_sha256=HELD_LOADER_SHA256,maintained=MAINTAINED,tree=TREE,central=b.CENTRAL,
            sdk_tag='3.9.5',sdk_source=SDK,sdk_tree=SDK_TREE,presentation=PRESENTATION,presentation_tree=PRESENTATION_TREE,
            inputs=INPUTS,request_sha256=hashlib.sha256(REQUEST).hexdigest(),actor=b.ACTOR,workflow=b.WORKFLOW,
            route='one-manual-stable-pages-publication',start_by=b.START_BY,decision_max_age_seconds=300,
            freeze_main_and_310_tags=True,limits=b.LIMITS)
    
    def comment(identifier):
        row=b.get(f'repos/{b.REPO}/issues/comments/{identifier}')
        if row['user']['id']!=b.ACTOR or not row['issue_url'].endswith('/issues/315'): raise RuntimeError('Primary identity')
        return row
    
    class Original(b.Original):
        def __init__(self,root):
            super().__init__(root); self.merged=MAINTAINED
            self.report['actual_maintained_sha']=MAINTAINED
            self.report['dispatch_consumed']=0
    
        def subject(self,run):
            return (run['workflow_id']==b.WORKFLOW and run['head_sha']==MAINTAINED and run['head_branch']=='main'
                and run['event']=='workflow_dispatch' and run['actor']['id']==b.ACTOR and run['run_attempt']==1)
    
        def source(self):
            prefix=f'repos/{b.REPO}'
            if b.get(prefix+'/git/ref/heads/main')['object']['sha']!=MAINTAINED: raise RuntimeError('Maintained main changed')
            if b.get(prefix+'/git/commits/'+MAINTAINED)['tree']['sha']!=TREE: raise RuntimeError('Maintained tree changed')
            if b.get('repos/durable-workflow/.github/git/ref/heads/main')['object']['sha']!=b.CENTRAL: raise RuntimeError('Catalog changed')
            tag=b.get(prefix+'/git/ref/tags/3.9.5')['object']
            if tag['type']!='commit' or tag['sha']!=SDK: raise RuntimeError('Published tag changed')
            if b.get(prefix+'/git/commits/'+SDK)['tree']['sha']!=SDK_TREE: raise RuntimeError('Published SDK tree changed')
            release=b.get(prefix+'/releases/tags/3.9.5')
            if (release['id']!=437212955 or release['tag_name']!='3.9.5' or release['target_commitish']!=SDK
                or release['draft'] or release['prerelease'] or not release['published_at']): raise RuntimeError('Published release changed')
            if b.get(prefix+'/git/commits/'+PRESENTATION)['tree']['sha']!=PRESENTATION_TREE: raise RuntimeError('Presentation tree changed')
            ancestry=b.get(prefix+'/compare/'+PRESENTATION+'...'+MAINTAINED)
            if ancestry['status']!='ahead' or ancestry['merge_base_commit']['sha']!=PRESENTATION: raise RuntimeError('Presentation ancestry changed')
            workflow=b.get(prefix+f'/actions/workflows/{b.WORKFLOW}')
            if workflow['id']!=b.WORKFLOW or workflow['path']!='.github/workflows/docs.yml' or workflow['state']!='active': raise RuntimeError('Workflow changed')
            rollback_tag=b.get(prefix+'/git/ref/tags/3.9.4')['object']
            if rollback_tag.get('sha')!=ROLLBACK['sdk_tag_object'] or rollback_tag.get('type')!='tag':
                raise RuntimeError('Rollback tag changed')
            rollback_object=b.get(prefix+'/git/tags/'+ROLLBACK['sdk_tag_object'])['object']
            if rollback_object['sha']!=ROLLBACK['sdk_source'] or rollback_object['type']!='commit': raise RuntimeError('Rollback product changed')
            rollback_release=b.get(prefix+'/releases/tags/3.9.4')
            if rollback_release['id']!=433546777 or rollback_release['draft'] or rollback_release['prerelease'] or not rollback_release['published_at']:
                raise RuntimeError('Rollback release unavailable')
            if b.get(prefix+'/git/commits/'+ROLLBACK['docs_source'])['tree']['sha']!='20409ff5493dd9e2bcc560f14f701393decf1997':
                raise RuntimeError('Rollback documentation source changed')
            pages=b.get(prefix+'/pages')
            if (pages['build_type']!='workflow' or pages['cname']!='php.durable-workflow.com'
                or pages['html_url']!='https://php.durable-workflow.com/' or pages['https_enforced'] is not True
                or pages['source']!={'branch':'main','path':'/'}): raise RuntimeError('Pages configuration changed')
            environment=b.get(prefix+'/environments/github-pages')
            if (environment['name']!='github-pages'
                or environment['deployment_branch_policy']!={'custom_branch_policies':True,'protected_branches':False}
                or [(r['id'],r['type']) for r in environment['protection_rules']]!=[(59824690,'branch_policy')]):
                raise RuntimeError('Pages protection changed')
            policy=b.get(prefix+'/environments/github-pages/deployment-branch-policies')
            if (policy['total_count']!=1 or [(r['id'],r['name'],r['type']) for r in policy['branch_policies']]!=[(54542139,'main','branch')]):
                raise RuntimeError('Pages branch admission changed')
            deployments=b.get(prefix+'/deployments?environment=github-pages&per_page=100')
            if not deployments or deployments[0]['id']!=LIVE_DEPLOYMENT: raise RuntimeError('Prior live deployment changed')
            status=b.get(prefix+f'/deployments/{LIVE_DEPLOYMENT}/statuses')
            if not status or status[0]['id']!=LIVE_STATUS or status[0]['state']!='success': raise RuntimeError('Prior live status changed')
            self.preview_only()
    
        def admit(self,decision_id,packet_id):
            decision=comment(decision_id); selection=json.loads(decision['body']); review=selection.get('review')
            if not isinstance(review,dict) or set(review)!={'id','body_sha256'}: raise RuntimeError('Review shape')
            reviewed=comment(review['id']); packet=comment(packet_id); predecessor=comment(PREDECESSOR['id'])
            if hashlib.sha256(predecessor['body'].encode()).hexdigest()!=PREDECESSOR['body_sha256']: raise RuntimeError('Stable build-only acceptance changed')
            if hashlib.sha256(reviewed['body'].encode()).hexdigest()!=review['body_sha256']: raise RuntimeError('Review changed')
            header=reviewed['body'].split('\n\n',1)[0]
            if '**PASS**' not in header or 'HOLD' in header or 'NONPASS' in header: raise RuntimeError('Affirmative stable effect review required')
            wanted=expected(packet_id,hashlib.sha256(packet['body'].encode()).hexdigest(),review)
            if any(value not in header for value in (wanted['controller_sha256'],BASE_CONTROLLER,str(packet_id),wanted['packet_body_sha256'],wanted['loader_sha256'])):
                raise RuntimeError('Stable controller/primitive/packet review binding')
            if selection!=wanted: raise RuntimeError('Closed stable selection differs')
            for key in ('owner','acceptance'):
                authority=comment(ROLLBACK[key]['id'])
                if hashlib.sha256(authority['body'].encode()).hexdigest()!=ROLLBACK[key]['body_sha256']:
                    raise RuntimeError('Rollback authority changed')
                if key=='acceptance' and not authority['body'].startswith('**TERMINAL / ARTIFACT / NONDEPLOYMENT / CLEANUP PASS**'):
                    raise RuntimeError('Rollback qualification not accepted')
            self.fresh(decision)
            if b.get('user')['id']!=b.ACTOR: raise RuntimeError('Actor changed')
            self.source()
            checks=b.get(f'repos/{b.REPO}/commits/{MAINTAINED}/check-runs?per_page=100')['check_runs']
            if (len(checks)!=46 or sum(row['conclusion']=='success' for row in checks)!=42
                or sorted(row['name'] for row in checks if row['conclusion']=='skipped')!=['Connected cooperative cancellation','deploy','deploy','deploy']
                or any(row['status']!='completed' or row['conclusion'] not in ('success','skipped') for row in checks)):
                raise RuntimeError('Maintained qualification changed')
            self.idle()
            self.before_deployments=b.get(f'repos/{b.REPO}/deployments?environment=github-pages&per_page=100')
            self.save('deployments-before.json',self.before_deployments)
            self.save('admission.json',{'decision':decision_id,'selection':selection})
            return decision
    
        def idle(self):
            for status in ('queued','in_progress','waiting'):
                if self.stop: raise RuntimeError('Stopped before publisher check')
                active=b.get(f'repos/{b.REPO}/actions/workflows/{b.WORKFLOW}/runs?status={status}&per_page=100')
                if active['total_count']!=0: raise RuntimeError('Publisher already active')
    
        def execute(self,decision_id,packet_id):
            decision=self.admit(decision_id,packet_id)
            self.source(); self.fresh(decision)
            self.consume('dispatch',REQUEST); self.report['dispatch_consumed']=1
            # Consumption can block or deliver a stop signal. Revalidate the selected
            # authority and competing publisher immediately before the provider write.
            self.fresh(decision); self.source(); self.idle(); self.fresh(decision)
            self.begun=b.now(); started=b.time.monotonic()
            self.report['dispatch_posts']=1; acknowledged=False
            self.report['t0']=self.begun.isoformat()
            try:
                response=b.gh('api',f'repos/{b.REPO}/actions/workflows/{b.WORKFLOW}/dispatches','--method','POST','--include','--input','-',input_bytes=REQUEST)
                acknowledged=re.match(rb'HTTP/[0-9.]+ 204(?:\s|$)',response) is not None
                self.report['dispatch_ack']='204' if acknowledged else 'unknown_status'
            except Exception as error: self.report['dispatch_ack']='unknown:'+type(error).__name__
            deadline=b.time.monotonic()+120
            while b.time.monotonic()<deadline:
                rows=b.get(f'repos/{b.REPO}/actions/workflows/{b.WORKFLOW}/runs?event=workflow_dispatch&per_page=100')['workflow_runs']
                matches=[row for row in rows if self.subject(row) and b.stamp(row['created_at'])>=self.begun-b.dt.timedelta(seconds=2)]
                if len(matches)>1: raise RuntimeError('Ambiguous stable discovery; no broad cancellation')
                if matches: self.run_id=matches[0]['id']; break
                b.time.sleep(5)
            if self.run_id is None: raise RuntimeError('No stable original handle; no repeat')
            self.report['run_id']=self.run_id
            self.save('bound-run.json',{'id':self.run_id,'t0':self.begun.isoformat(),'maintained':MAINTAINED})
            observed_started=False
            while b.time.monotonic()-started<1200:
                if self.stop: raise RuntimeError('Stop requested')
                run=b.get(f'repos/{b.REPO}/actions/runs/{self.run_id}')
                if not self.subject(run): raise RuntimeError('Stable subject changed')
                if run['status']=='completed':
                    self.save('run.json',run)
                    jobs=b.get(f'repos/{b.REPO}/actions/runs/{self.run_id}/attempts/1/jobs?per_page=100'); self.save('jobs.json',jobs)
                    self.save('artifacts.json',b.get(f'repos/{b.REPO}/actions/runs/{self.run_id}/artifacts?per_page=100'))
                    after=b.get(f'repos/{b.REPO}/deployments?environment=github-pages&per_page=100')
                    self.save('deployments-after.json',after)
                    self.save('exact-deployments.json',b.get(f'repos/{b.REPO}/deployments?sha={MAINTAINED}&environment=github-pages&per_page=100'))
                    builders=[row for row in jobs['jobs'] if row['name']=='build']
                    deployers=[row for row in jobs['jobs'] if row['name']=='deploy']
                    if len(builders)!=1 or len(deployers)!=1 or jobs['total_count']!=len(jobs['jobs']): raise RuntimeError('Stable terminal capture incomplete')
                    logs=b.gh('api','--allow-escape-sequences',f"repos/{b.REPO}/actions/jobs/{builders[0]['id']}/logs")
                    self.save_bytes('build-raw.log',logs)
                    deploy_logs=b.gh('api','--allow-escape-sequences',f"repos/{b.REPO}/actions/jobs/{deployers[0]['id']}/logs")
                    self.save_bytes('deploy-raw.log',deploy_logs)
                    before=self.before_deployments
                    new=[row for row in after if row['id'] not in {old['id'] for old in before}]
                    if len(new)!=1 or new[0]['sha']!=MAINTAINED or new[0]['environment']!='github-pages':
                        raise RuntimeError('Selected publication deployment attribution differs')
                    deployment=new[0]['id']; self.report['deployment_id']=deployment
                    self.save('deployment-statuses.json',b.get(f'repos/{b.REPO}/deployments/{deployment}/statuses'))
                    self.report.update(deploy_log_sha256=hashlib.sha256(deploy_logs).hexdigest(),deploy_log_bytes=len(deploy_logs))
                    self.report.update(build_log_sha256=hashlib.sha256(logs).hexdigest(),build_log_bytes=len(logs),conclusion=run['conclusion'])
                    if not acknowledged: raise RuntimeError('Dispatch acknowledgement remains uncertain; actual terminal captured')
                    self.report['outcome']='TERMINAL_CAPTURED_REQUIRES_AUDIT'; return
                observed_started=observed_started or run['status']=='in_progress'
                if not observed_started and b.time.monotonic()-started>300: raise RuntimeError('Stable start deadline expired')
                b.time.sleep(15)
            raise RuntimeError('Stable observation deadline expired')
    
    def main():
        parser=argparse.ArgumentParser();parser.add_argument('--decision',type=int,required=True);parser.add_argument('--packet',type=int,required=True)
        args=parser.parse_args()
        if __debug__ is False: raise RuntimeError('Optimized Python not admitted')
        os.umask(0o077);root=Path(tempfile.gettempdir())/('sdk-php-315-publication-'+str(args.packet));root.mkdir(mode=0o700)
        original=Original(root)
        def stop(signum,frame): original.stop=True
        signal.signal(signal.SIGTERM,stop);signal.signal(signal.SIGINT,stop)
        try: original.execute(args.decision,args.packet)
        except BaseException as error: original.report['error']=type(error).__name__+':'+str(error)
        finally:
            try: original.cancel()
            except BaseException as error: original.report['cleanup_error']=type(error).__name__+':'+str(error)
            original.report['ended_at']=b.now().isoformat()
            try: original.save('terminal.json',original.report)
            finally: os.close(original.directory)
        print(json.dumps(original.report,sort_keys=True))
        return 0 if original.report['outcome']=='TERMINAL_CAPTURED_REQUIRES_AUDIT' and 'cleanup_error' not in original.report else 1
    
    if __name__=='__main__': raise SystemExit(main())

    Inert controls: 20,037B / SHA256 cd04ad00482a101917789e1ceaace0f178fc935d1a6166ca319076c9410f1c3e.

    """Source-only controls: no live API, process, acquisition or publisher call."""
    import datetime as dt,hashlib,importlib.util,json,os,tempfile,unittest
    from pathlib import Path
    from unittest.mock import patch
    
    ROOT=Path(__file__).parent
    def load_controller(path):
        held=path.read_bytes()
        spec=importlib.util.spec_from_file_location('held_publication',path)
        module=importlib.util.module_from_spec(spec)
        module.__dict__['__held_source_bytes__']=held
        exec(compile(held,str(path),'exec'),module.__dict__)
        return module
    m=load_controller(ROOT/'publication-v2-once.py')
    FIXED=dt.datetime(2026,11,7,10,5,tzinfo=dt.timezone.utc)
    
    class Fixture:
        def __init__(self):
            self.writes=[];self.raw_calls=[];self.expired=False;self.unknown=False;self.ambiguous=False;self.active=False
            self.main=m.MAINTAINED;self.sdk=m.SDK;self.draft=False;self.tag=False
            self.tag_object=m.ROLLBACK['sdk_tag_object'];self.dispatched=False;self.new_sha=m.MAINTAINED;self.duplicate_deploy=False;self.page_host='php.durable-workflow.com';self.live_deployment=m.LIVE_DEPLOYMENT;self.live_status='success'
            self.owner='Exact accepted rollback owner.';self.acceptance='**TERMINAL / ARTIFACT / NONDEPLOYMENT / CLEANUP PASS**\n\nAccepted rollback.'
            self.packet='Exact distinct stable packet.';self.predecessor='Accepted prior actual stable build.'
            self.review='**PASS** finite stable effect review '+m.EXECUTING_SOURCE_SHA256+' '+m.BASE_CONTROLLER+' '+m.HELD_LOADER_SHA256+' packet 900 '+hashlib.sha256(self.packet.encode()).hexdigest()+'\n\nExact packet/source review.'
            self.selection=m.expected(900,hashlib.sha256(self.packet.encode()).hexdigest(),{'id':901,'body_sha256':hashlib.sha256(self.review.encode()).hexdigest()})
            self.checks=[dict(name=str(i),status='completed',conclusion='success') for i in range(42)]
            self.checks.extend([dict(name=name,status='completed',conclusion='skipped') for name in ('Connected cooperative cancellation','deploy','deploy','deploy')])
            self.run=dict(id=987,workflow_id=m.b.WORKFLOW,head_sha=m.MAINTAINED,head_branch='main',event='workflow_dispatch',
                actor={'id':m.b.ACTOR},run_attempt=1,created_at=FIXED.isoformat(),status='completed',conclusion='success')
        def comment(self,body):
            return dict(user={'id':m.b.ACTOR},issue_url=f'https://api.github.com/repos/{m.b.REPO}/issues/315',body=body,
                created_at=(FIXED-dt.timedelta(seconds=301 if self.expired else 1)).isoformat())
        def get(self,path):
            prefix=f'repos/{m.b.REPO}'
            comments={900:self.packet,901:self.review,902:json.dumps(self.selection),m.PREDECESSOR['id']:self.predecessor,
                m.ROLLBACK['owner']['id']:self.owner,m.ROLLBACK['acceptance']['id']:self.acceptance}
            for identifier,body in comments.items():
                if path==prefix+f'/issues/comments/{identifier}': return self.comment(body)
            if path=='user': return {'id':m.b.ACTOR}
            if path=='repos/durable-workflow/.github/git/ref/heads/main': return {'object':{'sha':m.b.CENTRAL}}
            if path==prefix+'/git/ref/heads/main': return {'object':{'sha':self.main}}
            if path==prefix+'/git/ref/tags/3.9.5':return {'object':{'type':'commit','sha':self.sdk}}
            if path==prefix+'/git/ref/tags/3.9.4': return {'object':{'type':'tag','sha':self.tag_object}}
            if path==prefix+'/git/tags/'+m.ROLLBACK['sdk_tag_object']:return {'tag':'3.9.4','object':{'type':'commit','sha':m.ROLLBACK['sdk_source']}}
            for source,tree in ((m.MAINTAINED,m.TREE),(m.SDK,m.SDK_TREE),(m.PRESENTATION,m.PRESENTATION_TREE),(m.ROLLBACK['docs_source'],'20409ff5493dd9e2bcc560f14f701393decf1997')):
                if path==prefix+'/git/commits/'+source:return {'tree':{'sha':tree}}
            if path==prefix+'/releases/tags/3.9.5':return dict(id=437212955,tag_name='3.9.5',target_commitish=m.SDK,draft=self.draft,prerelease=False,published_at=FIXED.isoformat())
            if path==prefix+'/releases/tags/3.9.4': return dict(id=433546777,tag_name='3.9.4',target_commitish='main',draft=False,prerelease=False,published_at=FIXED.isoformat())
            if '/compare/' in path: return {'status':'ahead','merge_base_commit':{'sha':m.PRESENTATION}}
            if path==prefix+f'/actions/workflows/{m.b.WORKFLOW}': return {'id':m.b.WORKFLOW,'path':'.github/workflows/docs.yml','state':'active'}
            if '/git/matching-refs/tags/3.10.0' in path:return [{'ref':'refs/tags/3.10.0'}] if self.tag else []
            if '/check-runs?' in path:return {'check_runs':self.checks}
            if '/runs?status=' in path:return {'total_count':1 if self.active else 0,'workflow_runs':[]}
            if path==prefix+'/pages':return dict(build_type='workflow',cname=self.page_host,html_url='https://php.durable-workflow.com/',https_enforced=True,source={'branch':'main','path':'/'})
            if path==prefix+'/environments/github-pages':return dict(name='github-pages',deployment_branch_policy={'custom_branch_policies':True,'protected_branches':False},protection_rules=[{'id':59824690,'type':'branch_policy'}])
            if path==prefix+'/environments/github-pages/deployment-branch-policies':return {'total_count':1,'branch_policies':[{'id':54542139,'name':'main','type':'branch'}]}
            if path==prefix+f'/deployments/{m.LIVE_DEPLOYMENT}/statuses':return [{'id':m.LIVE_STATUS,'state':self.live_status}]
            if path==prefix+f'/deployments/{m.LIVE_DEPLOYMENT+1}/statuses':return [{'id':m.LIVE_STATUS+1,'state':'success','log_url':'https://github.com/durable-workflow/sdk-php/actions/runs/987/job/655','environment_url':'https://php.durable-workflow.com/'}]
            if '/deployments?' in path:
                old=[{'id':self.live_deployment}]
                new={'id':m.LIVE_DEPLOYMENT+1,'sha':self.new_sha,'environment':'github-pages'}
                if self.dispatched:return ([new,dict(new,id=new['id']+1)] if self.duplicate_deploy else [new])+old
                return old
            if '/runs?event=workflow_dispatch' in path:return {'workflow_runs':[self.run]*(2 if self.ambiguous else 1)}
            if path==prefix+'/actions/runs/987':return self.run
            if '/attempts/1/jobs?' in path:return {'total_count':2,'jobs':[{'id':654,'name':'build'},{'id':655,'name':'deploy'}]}
            if '/artifacts?' in path:return {'total_count':2,'artifacts':[]}
            raise AssertionError('Unexpected read '+path)
        def gh(self,*arguments,input_bytes=None):
            if '--method' not in arguments:
                self.raw_calls.append(arguments)
                if '--allow-escape-sequences' not in arguments: raise AssertionError('Raw-log opt-in absent')
                return b'\x1b[32mprivate mocked raw log\n'
            self.writes.append((arguments,input_bytes));self.dispatched=True
            if not arguments[1].endswith('/dispatches'): raise AssertionError('Unexpected protected mutation')
            if self.unknown: raise RuntimeError('unknown acknowledgement')
            return b'HTTP/2.0 204 No Content\r\n\r\n'
    
    class Controls(unittest.TestCase):
        def setUp(self):
            self.temp=tempfile.TemporaryDirectory(prefix='sdk-php-stable-inert-');self.root=Path(self.temp.name);self.root.chmod(0o700)
            self.original=m.Original(self.root)
            self.predecessor=patch.dict(m.PREDECESSOR,{'body_sha256':hashlib.sha256(b'Accepted prior actual stable build.').hexdigest()});self.predecessor.start()
            self.rollback=patch.dict(m.ROLLBACK,{
                'owner':{'id':6706622929,'body_sha256':hashlib.sha256(b'Exact accepted rollback owner.').hexdigest()},
                'acceptance':{'id':6706641997,'body_sha256':hashlib.sha256(b'**TERMINAL / ARTIFACT / NONDEPLOYMENT / CLEANUP PASS**\n\nAccepted rollback.').hexdigest()}});self.rollback.start()
            self.fixture=Fixture()
            self.patches=[patch.object(m.b,'get',self.fixture.get),patch.object(m.b,'gh',self.fixture.gh),patch.object(m.b,'now',lambda:FIXED),patch.object(m.b.time,'sleep',lambda seconds:None)]
            for item in self.patches:item.start()
        def tearDown(self):
            for item in reversed(self.patches):item.stop()
            self.rollback.stop();self.predecessor.stop();os.close(self.original.directory);self.temp.cleanup()
        def execute(self):self.original.execute(902,900)
        def test_exact_one_typed_publication_and_raw_build_deploy_capture(self):
            self.execute()
            self.assertEqual(len(self.fixture.writes),1)
            request=json.loads(self.fixture.writes[0][1]);self.assertIs(request['inputs']['build_only'],False)
            self.assertEqual(request,{'ref':'main','inputs':m.INPUTS})
            self.assertEqual(request['inputs']['stable_tag'],'3.9.5')
            self.assertEqual(request['inputs']['stable_source'],'')
            self.assertEqual(request['inputs']['presentation_source'],m.PRESENTATION)
            self.assertEqual(self.original.report['dispatch_ack'],'204')
            self.assertEqual(self.original.report['outcome'],'TERMINAL_CAPTURED_REQUIRES_AUDIT')
            self.assertEqual((self.original.report['ready_posts'],self.original.report['merge_puts']),(0,0))
            self.assertTrue(all('--allow-escape-sequences' in x for x in self.fixture.raw_calls));self.assertEqual(len(self.fixture.raw_calls),2)
            self.assertEqual(self.original.report['deployment_id'],m.LIVE_DEPLOYMENT+1)
        def test_unknown_dispatch_ack_is_consumed_once_and_observed_without_retry(self):
            self.fixture.unknown=True
            with self.assertRaisesRegex(RuntimeError,'acknowledgement remains uncertain'):self.execute()
            self.assertEqual(len(self.fixture.writes),1);self.assertTrue((self.root/'run.json').exists())
            self.assertEqual(self.original.report['outcome'],'NONPASS')
        def test_stale_selection_zero_writes(self):
            self.fixture.expired=True
            with self.assertRaisesRegex(RuntimeError,'expired'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_main_zero_writes(self):
            self.fixture.main='b'*40
            with self.assertRaisesRegex(RuntimeError,'main changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_published_tag_zero_writes(self):
            self.fixture.sdk='b'*40
            with self.assertRaisesRegex(RuntimeError,'Published tag changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_unpublished_release_zero_writes(self):
            self.fixture.draft=True
            with self.assertRaisesRegex(RuntimeError,'release changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_preview_acceptance_zero_writes(self):
            self.fixture.predecessor+=' changed'
            with self.assertRaisesRegex(RuntimeError,'Stable build-only acceptance changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_build_only_true_in_publication_selection_zero_writes(self):
            self.fixture.selection['inputs']=dict(m.INPUTS,build_only=True)
            with self.assertRaisesRegex(RuntimeError,'selection differs'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_present_310_tag_zero_writes(self):
            self.fixture.tag=True
            with self.assertRaisesRegex(RuntimeError,'tag is no longer absent'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_checks_zero_writes(self):
            self.fixture.checks[0]['conclusion']='failure'
            with self.assertRaisesRegex(RuntimeError,'qualification changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_ambiguous_run_has_no_repeat_or_broad_cancel(self):
            self.fixture.ambiguous=True
            with self.assertRaisesRegex(RuntimeError,'Ambiguous stable'):self.execute()
            self.original.cancel();self.assertEqual(len(self.fixture.writes),1)
        def test_changed_cancellation_subject_has_no_mutation(self):
            self.original.run_id=987;self.fixture.run['head_sha']='b'*40
            with self.assertRaisesRegex(RuntimeError,'subject changed'):self.original.cancel()
            self.assertEqual(self.fixture.writes,[])
        def test_unreviewed_primitive_bytes_refuse_before_import(self):
            with tempfile.TemporaryDirectory(prefix='sdk-php-primitive-negative-') as directory:
                copy=Path(directory)/'publication-v2-once.py';copy.write_bytes(Path(m.__file__).read_bytes())
                copy.with_name('preview-once.py').write_text('raise AssertionError("unreviewed execution")\n')
                with self.assertRaisesRegex(RuntimeError,'primitive source changed'):load_controller(copy)
    
        def test_changed_annotated_tag_object_zero_writes(self):
            self.fixture.tag_object='b'*40
            with self.assertRaisesRegex(RuntimeError,'Rollback tag changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_presentation_donor_in_selection_zero_writes(self):
            self.fixture.selection['inputs']=dict(m.INPUTS,presentation_source='a'*40)
            with self.assertRaisesRegex(RuntimeError,'selection differs'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_pages_host_zero_writes(self):
            self.fixture.page_host='other.example.test'
            with self.assertRaisesRegex(RuntimeError,'Pages configuration changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_live_deployment_zero_writes(self):
            self.fixture.live_deployment+=1
            with self.assertRaisesRegex(RuntimeError,'Prior live deployment changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_failed_live_status_zero_writes(self):
            self.fixture.live_status='failure'
            with self.assertRaisesRegex(RuntimeError,'Prior live status changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_protected_branch_policy_zero_writes(self):
            old=self.fixture.get
            def get(path):
                row=old(path)
                if path.endswith('/deployment-branch-policies'):row['branch_policies'][0]['name']='other'
                return row
            with patch.object(m.b,'get',get):
                with self.assertRaisesRegex(RuntimeError,'Pages branch admission changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
    
        def test_changed_rollback_owner_refuses_before_write(self):
            self.fixture.owner+=' changed'
            with self.assertRaisesRegex(RuntimeError,'Rollback authority changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_changed_rollback_acceptance_refuses_before_write(self):
            self.fixture.acceptance+=' changed'
            with self.assertRaisesRegex(RuntimeError,'Rollback authority changed'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_wrong_new_deployment_head_is_consumed_not_repeated(self):
            self.fixture.new_sha='b'*40
            with self.assertRaisesRegex(RuntimeError,'deployment attribution differs'):self.execute()
            self.assertEqual(len(self.fixture.writes),1)
        def test_multiple_new_deployments_refuse_without_repeat(self):
            self.fixture.duplicate_deploy=True
            with self.assertRaisesRegex(RuntimeError,'deployment attribution differs'):self.execute()
            self.assertEqual(len(self.fixture.writes),1)
    
        def test_edited_packet_with_unchanged_review_refuses_zero_posts(self):
            self.fixture.packet+=' edited after review'
            self.fixture.selection=m.expected(900,hashlib.sha256(self.fixture.packet.encode()).hexdigest(),self.fixture.selection['review'])
            with self.assertRaisesRegex(RuntimeError,'review binding'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_stop_delivered_by_consumption_refuses_zero_posts(self):
            consume=self.original.consume
            def stop(name,body):
                consume(name,body);self.original.stop=True
            with patch.object(self.original,'consume',stop):
                with self.assertRaisesRegex(RuntimeError,'Stopped or selection expired'):self.execute()
            self.assertEqual(self.fixture.writes,[])
            self.assertEqual(self.original.report['dispatch_posts'],0)
            self.assertTrue((self.root/'dispatch-consumed.json').exists())
        def test_new_active_publisher_after_admission_refuses_zero_posts(self):
            admit=self.original.admit
            def competing(*args):
                decision=admit(*args);self.fixture.active=True;return decision
            with patch.object(self.original,'admit',competing):
                with self.assertRaisesRegex(RuntimeError,'Publisher already active'):self.execute()
            self.assertEqual(self.fixture.writes,[])
            self.assertEqual(self.original.report['dispatch_posts'],0)
        def test_expired_selection_after_consumption_refuses_zero_posts(self):
            consume=self.original.consume
            def delayed(name,body):
                consume(name,body)
                self.patches.append(patch.object(m.b,'now',lambda:FIXED+dt.timedelta(seconds=301)))
                self.patches[-1].start()
            with patch.object(self.original,'consume',delayed):
                with self.assertRaisesRegex(RuntimeError,'expired'):self.execute()
            self.assertEqual(self.fixture.writes,[])
        def test_expected_uses_held_executing_bytes_after_path_replacement(self):
            with tempfile.TemporaryDirectory(prefix='sdk-php-held-source-control-') as directory:
                path=Path(directory)/'controller.py';held=Path(m.__file__).read_bytes();path.write_bytes(held)
                path.with_name('preview-once.py').write_bytes((ROOT/'preview-once.py').read_bytes())
                module=load_controller(path)
                path.write_text('raise AssertionError("replacement must not execute")\n')
                chosen=module.expected(900,'a'*64,{'id':901,'body_sha256':'b'*64})
                self.assertEqual(chosen['controller_sha256'],hashlib.sha256(held).hexdigest())
                self.assertNotEqual(chosen['controller_sha256'],hashlib.sha256(path.read_bytes()).hexdigest())
        def test_direct_path_execution_without_held_loader_refuses(self):
            path=ROOT/'publication-v2-once.py'
            spec=importlib.util.spec_from_file_location('unheld',path);module=importlib.util.module_from_spec(spec)
            with self.assertRaisesRegex(RuntimeError,'held-bytes loader'):spec.loader.exec_module(module)
        def test_literal_loader_executes_only_the_selected_held_fixture(self):
            with tempfile.TemporaryDirectory(prefix='sdk-php-loader-control-') as directory:
                path=Path(directory)/'fixture.py'
                body=b'from pathlib import Path\nassert isinstance(__held_source_bytes__,bytes)\nPath(__file__).with_name("executed").touch()\n'
                path.write_bytes(body)
                loader=(ROOT/'publication-held-loader.py').read_text()
                with patch('sys.argv',['loader',str(path),hashlib.sha256(body).hexdigest()]):
                    exec(compile(loader,'literal-loader','exec'),{})
                self.assertTrue(path.with_name('executed').exists())
        def test_literal_loader_wrong_digest_never_executes_fixture(self):
            with tempfile.TemporaryDirectory(prefix='sdk-php-loader-negative-') as directory:
                path=Path(directory)/'fixture.py';path.write_text('raise AssertionError("unselected code")\n')
                with patch('sys.argv',['loader',str(path),'a'*64]):
                    with self.assertRaisesRegex(RuntimeError,'held bytes differ'):
                        exec(compile((ROOT/'publication-held-loader.py').read_text(),'literal-loader','exec'),{})
        def test_literal_loader_rejects_writable_source_before_execution(self):
            with tempfile.TemporaryDirectory(prefix='sdk-php-loader-mode-') as directory:
                path=Path(directory)/'fixture.py';body=b'raise AssertionError("unselected code")\n';path.write_bytes(body);path.chmod(0o666)
                with patch('sys.argv',['loader',str(path),hashlib.sha256(body).hexdigest()]):
                    with self.assertRaisesRegex(RuntimeError,'file authority refused'):
                        exec(compile((ROOT/'publication-held-loader.py').read_text(),'literal-loader','exec'),{})
    
    if __name__=='__main__':unittest.main()
  23. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    PASS — finite effect review accepts the exact unexecuted SDK-PHP publication packet 6706837393, body SHA-256 9cafa16c8f121824d9f713193416136bc7635ad81716dfc7167d70329112dfea, executing adapter SHA-256 217d696b87dbffbc5796be0f4ca2293edbfa5bad330282cf1525bba8972a206d, sealed primitive SHA-256 c69c2dca60196d245b33a735d72dabdc1c918a628f21d4069a3c48043aecc067, and literal held-byte loader SHA-256 e0bba095c27166d967986e97f6fad0b7e3407f409c95cc980cd017755bff3614.

    The exact successor closes the four causal defects in the prior unexecuted subject. The authenticated review header now binds the packet ID and current packet-body digest plus all three executable identities; an edited packet cannot reuse this review. After exclusive/fsynced request consumption, the controller repeats stop/age/start-by freshness, the complete exact source/provider/rollback checks, all queued/in-progress/waiting publisher checks, and a final freshness check immediately before the provider call. A stop delivered by consumption or a newly active publisher therefore gives zero POSTs. The adapter refuses direct pathname execution; the reviewed loader holds and hashes one regular-file descriptor and compiles those same bytes, while the controller derives its selected identity only from that injected immutable snapshot.

    I independently matched the 57,923-byte primary packet to its local source and digest. Removing only each Markdown fence's terminating newline, the embedded 882-byte loader, 16,934-byte adapter, and 20,037-byte control source are byte-identical to the local subjects. All parse and compile, the adapter contains no assert, and all 32 inert candidate controls pass. The preserved predecessor fails all four causal controls: edited-packet/review reuse, stop-after-consumption, active-publisher-after-admission, and executing-source pathname replacement.

    The bound authority remains exact at review time: maintained main is bf40f8c419dd205a979ad16ceef87ceeebdee067; tag 3.9.5 resolves directly to 57562b53e429a2c3ae1e9aa531ed781e9429bd59; annotated rollback tag 3.9.4 is ceb70e243e0bb5237588ddb9abad742ad01dd964. Stable build-only acceptance 6705735224, rollback owner 6706622929, and independent rollback acceptance 6706641997 match their selected full body hashes. Current Pages remains workflow-built at the bound HTTPS domain.

    Effect authority is limited to one distinct General selection no older than 300 seconds and before 2026-11-07 13:30 UTC, selecting this exact closed v2 object. It permits one typed build_only=false workflow dispatch for stable 3.9.5/presentation a431 on maintained bf40; it permits no source, main, tag, release, ready, merge, account, secret, or rollback write. Unknown acknowledgement consumes the sole original and never permits retry. Only the uniquely bound workflow-dispatch/main/bf40/actor/attempt-1 run may be watched or cancelled, with at most one normal and one force cancellation under the reviewed 120-second discovery, 300-second start, 1,200-second watch, 90/60-second cancellation, 25-second child, 4 MiB stream, and 35-minute plus 180-second outer bounds.

    This PASS is not publication acceptance. The selected run must still return exact terminal context, successful build and deploy, canonical receipt-v5 and setup/pip/Composer cleanup, one newly attributed Pages deployment with successful exact-run status/log binding, bounded artifacts, and the source-bound live HTTPS tuple. Controller or audit uncertainty, stale live content after the stated bound, cleanup gaps, or provider ambiguity remain failures without retry or automatic rollback. The qualified 3.9.4 route is readiness evidence only; any rollback remains a distinct freshly reviewed and selected protected rebuild-and-deploy decision.

  24. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    {
    "actor": 1130888,
    "central": "edba47c8f9d3b9984731bc3fba4e1ab3299f1b9f",
    "controller_sha256": "217d696b87dbffbc5796be0f4ca2293edbfa5bad330282cf1525bba8972a206d",
    "decision_max_age_seconds": 300,
    "freeze_main_and_310_tags": true,
    "inputs": {
    "build_only": false,
    "presentation_source": "a4315bcdf62b4a8466c25bd007a9a9d6b06d1f45",
    "stable_source": "",
    "stable_tag": "3.9.5"
    },
    "limits": {
    "cancel_seconds": 90,
    "child_seconds": 25,
    "discovery_seconds": 120,
    "force_seconds": 60,
    "native_build_minutes": 25,
    "start_seconds": 300,
    "stream_bytes": 4194304,
    "watch_seconds": 1200
    },
    "loader_sha256": "e0bba095c27166d967986e97f6fad0b7e3407f409c95cc980cd017755bff3614",
    "maintained": "bf40f8c419dd205a979ad16ceef87ceeebdee067",
    "packet": 6706837393,
    "packet_body_sha256": "9cafa16c8f121824d9f713193416136bc7635ad81716dfc7167d70329112dfea",
    "predecessor": {
    "body_sha256": "14f2ee0e0af2d43bd8cffd6b78b9807eb3efc2bc2662ed5f504cec3a124d83c4",
    "id": 6705735224
    },
    "presentation": "a4315bcdf62b4a8466c25bd007a9a9d6b06d1f45",
    "presentation_tree": "7ce9a26c7d30f0bb67199b83f615d5fc5667cfc7",
    "primitive_sha256": "c69c2dca60196d245b33a735d72dabdc1c918a628f21d4069a3c48043aecc067",
    "request_sha256": "a0fe516ea5638cee00d4ab39870adae560322444b32612c90502caea2960e0a3",
    "review": {
    "body_sha256": "cab57eedcf124183781b2f6bb182a65faf59f852e4217ab1e38cc7f22953e604",
    "id": 6706873047
    },
    "rollback_authority": {
    "acceptance": {
    "body_sha256": "fc5503769b1974b134819aae330fb44f15e346f9abd5abeb7fe1d71c37f56417",
    "id": 6706641997
    },
    "active_seconds": 2100,
    "cleanup_seconds": 180,
    "docs_source": "6a821568db5c72983bd3990fe27c7990f092db12",
    "inputs": {
    "build_only": false,
    "presentation_source": "",
    "stable_source": "6a821568db5c72983bd3990fe27c7990f092db12",
    "stable_tag": "3.9.4"
    },
    "maintained": "bf40f8c419dd205a979ad16ceef87ceeebdee067",
    "owner": {
    "body_sha256": "8f39a44b3e525806f86c52cea9a0aafa59170b8abd2d98eb0714f44e3f1d2f96",
    "id": 6706622929
    },
    "qualification_run": 42369893733,
    "route": "distinct-freshly-selected-protected-full-rebuild-and-deploy",
    "sdk_source": "11085f0c624674a4b70d3a6fb3e83eaff3869fcb",
    "sdk_tag": "3.9.4",
    "sdk_tag_object": "ceb70e243e0bb5237588ddb9abad742ad01dd964"
    },
    "route": "one-manual-stable-pages-publication",
    "schema": "sdk-php.docs-stable-publication-selection/v2",
    "sdk_source": "57562b53e429a2c3ae1e9aa531ed781e9429bd59",
    "sdk_tag": "3.9.5",
    "sdk_tree": "6a58907fff58e1a4106514cbb094da4608778fe1",
    "start_by": "2026-11-07T13:30:00+00:00",
    "tree": "2e5ddc33382696ace11ba14ddc6b670373b517bb",
    "workflow": 312595210
    }

  25. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    The exact selected publication original is bound to run42372587642/a1, T0 2026-11-07T12:27:48.531260Z. Primary selection6706912800 matched the reviewed successor6706837393/PASS6706873047. The literal e0bba loader verified and compiled the same held217d Source bytes; current admission and post-consumption stop/source/provider/active/freshness gates passed. The one typed stable3.9.5/a431/bf40/build_only=false request was durably consumed before its POST. The bounded watcher remains active; actual acknowledgement, build/deploy terminal, canonical custody/cleanup, artifacts and live result follow. No retry, automatic rollback, main/tag change or PR350 merge is selected. SDK-PHP retains the complete observation/cancellation/cleanup scope; General has no additional observer duty.

  26. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    Actual stable3.9.5 Pages publication is terminal with owner artifact/live/cleanup PASS; independent acceptance requested. Run42372587642/a1 executed exact primary selection6706912800, successor packet6706837393 / finite PASS6706873047. The held predecessor6706719643/HOLD6706754233 stays historical. This original selected only stable3.9.5/a431/bf40/build_only=false; no retry, rollback, main/tag write or PR350 merge occurred.

    The reviewed literal loader e0bba095c27166d967986e97f6fad0b7e3407f409c95cc980cd017755bff3614 opened/verified/compiled the same held controller bytes 217d696b87dbffbc5796be0f4ca2293edbfa5bad330282cf1525bba8972a206d, with sealed c69 primitive. Full current admission and immediate post-consumption stop/source/provider/active/freshness checks passed. Requesta0fe was consumed at12:27:38.504960Z; actual POST T0 was 2026-11-07T12:27:48.531260Z. The controller records one consumption, exactly one POST / HTTP204, and zero ready/merge/retry/cancel/force operations.

    Actual workflow312595210/main/workflow_dispatch/actor1130888/attempt1 head+workflow source is bf40f8c419dd205a979ad16ceef87ceeebdee067. Run12:27:49–12:29:55Z is SUCCESS. Build128403594546 ran12:27:53–12:29:39Z, SUCCESS; deploy128403985097 ran12:29:42–12:29:55Z, SUCCESS. The bounded observer exited zero at12:30:05.517665Z, TERMINAL_CAPTURED_REQUIRES_AUDIT. Literal loader/controller/outer command are absent. No local container/image/network was created.

    Exactly one new github-pages deployment is 7621161301, sourcebf40. Latest successful status 21650396625,12:29:55Z, binds this exact deploy job and environment URL https://php.durable-workflow.com/. Captured before/after inventories differ by this one deployment; captured and fresh exact-bf40 queries return exactly7621161301. The existing Pages/CNAME/HTTPS/main-only environment configuration was not changed. No rollback was needed or performed.

    Bounded raw build log: 351,617B / SHA256 cd70721c3659acb73f5474db76931d9008dd47a6fc7aad63585704d6189fb822. Raw deploy log: 3,651B / SHA256 1e8e9be232fb907ed135576c0ea89a9334c2c19f9660e5a8f61b6fdf562560eb. Exactly one canonical durable-workflow.php-linux-terminal/v1 object proves pass/complete/productsuccess and all seven actual context fields: repositorysdk-php, run42372587642/a1, workflow_dispatch/main, GITHUB_SHA and GITHUB_WORKFLOW_SHA bothbf40. Product57562 is independently bound below.

    Canonical custody binds helper/control ed150, private-pip/Composer242c, configured receipt-v5 / SHA256 894d41950202567465f07b23cda49148e81ac48d129cfd37518458a0c57e772e, repository-held installer7bc5 and the accepted Ubuntu24.04/x86_64/PHP8.3.36 production/Composer2.10.3/PHPUnit11.5.57/coverage-none request. Post-product configuration/normalization/runtime/tool/loader/CA/alternatives/private-pip revalidation passes:9alternatives,484pip subjects, Python3.12.3/pip26.2.2. Setup cleanup PASS, pip cleanup PASS, independent held-identity Composer cleanup PASS. Normal required product commands ran and stable=true/source_revision57562 was observed. Owner strict terminal/deployment audit passed.

    Exact provider artifact Size / SHA256
    Visual13574622084,12PNGs 2,782,548B / 9e68d6cf1cc7cba5ca06cbb18f5140aeaf9452a970c8b49ec8815707374f7ee6
    Pages13574337709 1,038,049B / 24e0c24a8d934de545abe72ac98021b9f4864511a86c7764dbf82af68a1972cc

    Provider run/head/IDs/sizes/digests match. Bounded safe ZIP/TAR streaming executed no archive bytes and materialized no artifact directory tree. Pages has475members /13,244,631regular-file bytes, maximum720,373B. Owner artifact audit passed in3.037s. Its exact v2 audit is:

    {"schema":"durable-workflow.sdk-php.docs-deployment/v2","source_revision":"57562b53e429a2c3ae1e9aa531ed781e9429bd59","sdk_source_revision":"57562b53e429a2c3ae1e9aa531ed781e9429bd59","presentation_source_revision":"a4315bcdf62b4a8466c25bd007a9a9d6b06d1f45","published_sdk_source_revision":"57562b53e429a2c3ae1e9aa531ed781e9429bd59","published_sdk_version":"3.9.5","workflow_revision":"bf40f8c419dd205a979ad16ceef87ceeebdee067"}

    The selected3.9/^3.9/quickstart3.9.5 contract is present. Two bounded actual captures were viewed: home-desktop-light.png187,076B/SHA256 77dc187b6f933544175c72152f3a9416679226061a04b1eab8e6d9d22a22e50b; api-reference-mobile-dark.png95,577B/SHA256 23f8f8c66ac4084ed3bf5692d71aac1084b7c5373c48814c4c241dfc3a4278da. The One Identity header/footer, PHP series, runtime choices and mobile API navigation render coherently. Prior observer failures remain attributed to their earlier runs/readers; this publication's artifact audit passed directly.

    Actual live-site proof passed on the first bounded read-only attempt in0.359s. The public deployment audit equals the exact v2 tuple above, SHA256 2dd2c51b3b907d5c9d1e1d4283e3b08e697d0efb9c975faae6405c6dddafb7c4. The following fresh HTTPS200 responses equal the selected provider artifact bytes:

    • Home: SHA256 322065beefb717fd4dc242b8b7b928205281ee83dda6cb548c9b6e1a585ecefc.
    • API reference: SHA256 e789e117475fedcf9d6e08199a83a54c4d3ac90f7868e86b89496a61bd4ed141.
    • Quickstart contract, version3.9.5: SHA256 35f0671e304913b9c5806dc74ebf1a17a94509ae1dcfed2dbe187b6cf151034e.

    No stale response, extra build, deploy or cache mutation was used to obtain that result. Owner terminal/artifact/live audit objects are retained with the selected original. The evidence root is0700/files0600, no ZIP/TAR remains, and the declared reconciliation/retention deadline remains2026-11-08T12:00Z. Current main is stillbf40, tag3.10.0 absent; all 48 actual main checks are terminal, 44success /four intended skips (three earlier deploy jobs and connected cancellation). The selected publication's build and deploy succeeded.

    Please independently reconcile exact terminal/configured custody, new provider deployment/status/run attribution, artifacts/visuals, actual live bytes and cleanup. General then owns the final #315 completion and main/tag freeze disposition. The accepted prior-live3.9.4/6a821 full-rebuild rollback route remains ready but unselected; no rollback mutation is inferred. PR350, SDK3.10 publication, #328–#332 installed/Native/fallback/lease/load acceptance and Server's qualifier successor remain separate and open.

  27. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    PASS — exact stable 3.9.5 Pages publication terminal, artifact, live-byte, custody, and cleanup acceptance for selected packet 6706837393, decision 6706912800, and owner receipt 6706998180. This accepts only run 42372587642 attempt 1 and its resulting Pages deployment. The earlier observer/controller NONPASS results remain historical; no retry, rollback, PR350 merge, main mutation, or tag mutation is accepted or inferred.

    Independent reconciliation of the retained packet-owned evidence confirms:

    • The held-byte loader/controller chain is the reviewed e0bba095… / 217d696b… / sealed c69c2dca… subject. Consumption and immediate post-consumption gates preceded the one HTTP 204 POST at T0 2026-11-07T12:27:48.531260Z. No ready, merge, retry, normal-cancel, or force-cancel call occurred.
    • Run 42372587642/a1 is the exact workflow_dispatch / main / actor 1130888 / workflow 312595210 / source bf40f8c419dd205a979ad16ceef87ceeebdee067 original. It is terminal SUCCESS. Build job 128403594546 and deploy job 128403985097 are both terminal SUCCESS.
    • Exactly one fresh Pages deployment is attributable to this original: deployment 7621161301, exact source bf40…, with latest status 21650396625 SUCCESS and the exact deploy-job URL. The captured before/after and exact-source inventories agree.
    • The 351,617-byte build log hashes to cd70721c3659acb73f5474db76931d9008dd47a6fc7aad63585704d6189fb822; the 3,651-byte deploy log hashes to 1e8e9be232fb907ed135576c0ea89a9334c2c19f9660e5a8f61b6fdf562560eb. The single canonical terminal object is pass/complete/product-success and binds the seven actual context fields. Receipt-v5 SHA-256 is 894d41950202567465f07b23cda49148e81ac48d129cfd37518458a0c57e772e; setup, private-pip, and the separate Composer-state cleanup all pass. Nine alternatives and 484 private-pip subjects revalidate.
    • Provider artifact 13574622084 is 2,782,548 bytes / SHA-256 9e68d6cf1cc7cba5ca06cbb18f5140aeaf9452a970c8b49ec8815707374f7ee6; artifact 13574337709 is 1,038,049 bytes / SHA-256 24e0c24a8d934de545abe72ac98021b9f4864511a86c7764dbf82af68a1972cc. The Pages artifact has 475 page members, 13,244,631 regular-file bytes, and a 720,373-byte maximum member. Its deployment-audit tuple is exactly published SDK/source 57562b53e429a2c3ae1e9aa531ed781e9429bd59, presentation a4315bcdf62b4a8466c25bd007a9a9d6b06d1f45, workflow bf40…, version 3.9.5.
    • The bounded live audit passed on its first attempt. Public deployment-audit.json binds that same tuple. Live HTTPS home, API, and quickstart bytes equal the selected artifact at SHA-256 322065be…, e789e117…, and 35f0671e…. I independently viewed home-desktop-light.png (77dc187b…) and api-reference-mobile-dark.png (23f8f8c…): the PHP 3.9 series, navigation, runtime choices, API layout, and One Identity header/footer render coherently without a visible error or missing-content state.
    • Current main remains bf40…; the 3.10.0 tag-freeze query is empty. All 48 captured main checks are terminal: 44 SUCCESS and four intended skips. The evidence directory is mode 0700 with 24 mode-0600 files, contains no retained ZIP/TAR, has no open file or owner process, and the loader/controller/outer process is absent.

    Disposition: the stable 3.9.5 Pages publication and its exact public bytes are accepted. The prior-live 3.9.4 full-rebuild rollback route remains available but unselected. SDK 3.10/PR350, installed/native/profile/load qualifications, and any later publication remain separate gates. General retains final issue completion and freeze disposition.

  28. rmcdaniel commented on Nov 7, 2026

    @rmcdaniel
    MemberAuthor

    General accepts and closes the actual SDK315 publisher outcome: stable PHP SDK3.9.5 is published through the protected Pages workflow. Owner6706998180 and independent final6707019266 bind run42372587642/a1, new deployment7621161301/status21650396625, exact57562/a431/bf40/v2-live tuple, canonical terminal and setup/private-pip/Composer cleanup, matching artifacts/public bytes and absent controller. One POST, zero retry/cancel/rollback/source/tag mutation; all48 current checks terminal44success/4intendedskip. The earlier observer NONPASSs remain attributed.

    This completes315's actual first-caller/publisher qualification and user-visible stable publication. Clean only completed owned340/topic resources under their exact qualified identities; preserve active350/219 and all operator WIP. The prior bf40 publication freeze is discharged for that completed subject, but no blanket main/tag write is granted.

    Next: advance the qualified350 Source cohort through a complete normal-ready/merge→automatic-preview proposal on exact basebf40/headdcea/tree155349, capturing the returned main SHA and retaining existing workflow bytes/central policy/profile. Reuse the accepted bounded merge/observer primitive and return the full trigger/terminal/cleanup graph for its distinct General selection. This is preparation authority only; actual350 merge/preview remains unselected. Release3.10 tag/publication and installed/native qualification remain under293, not this closure. The qualified prior3.9.4 rollback route remains readiness only unless separately selected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:sdk-phpWork done by the sdk-php repo agentpriority:P0Immediate release or data-integrity riskstatus:blockedWaiting on a named dependency or decision

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions