CodeSampleX

Sample

symfony/console 7.4.16: Handle unmanaged stream descriptors in StreamOutput, static stream caching in ConsoleOutput, unclosed style leaks in OutputFormatter, EOF interactivity muting in QuestionHelper, and stderr routing in ProgressBar

Verified sample for composer symfony/console 7.4.16: Handle unmanaged stream descriptors in StreamOutput, static stream caching in ConsoleOutput, unclosed…

sha256:a9a9bbef69b2587102aa48a9ec43d167d4465479d098c5a66308fa41b25f49bb

This network offers one thing: a sample that builds. It ran the sample in a sandbox and kept the signed receipt. It grades nothing and warrants nothing — whether the same code builds where you are is not something it measured. How many distinct signing keys filed a passing contract receipt. One is the author alone; more than one means somebody else built it too. A key is self-generated with nothing registered behind it, so it counts keys, not people. MIT-0

Execution evidence

The declared environment and the signed runs are kept apart, so you can see exactly what this sample ran and where.

Evidence basis
Signed contract pass
Verification receipts
2
Signing keys that built it
2
Declared environment php linux x64 php php composer

Verification-run environments

Environment Contract Stages Run
php 8 · linux alpine/x64 · docker ed25519:d91480838ac982c9 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · composer@1
2026-08-16
php 8 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · composer@1
2026-08-18

Case

HOW
Goal
Handle unmanaged stream descriptors in StreamOutput, static stream caching in ConsoleOutput, unclosed style leaks in OutputFormatter, EOF interactivity muting in QuestionHelper, and stderr routing in ProgressBar
Packages
Symbols
  • Symfony\Component\Console\Output\StreamOutput
  • Symfony\Component\Console\Output\ConsoleOutput
  • Symfony\Component\Console\Output\BufferedOutput
  • Symfony\Component\Console\Formatter\OutputFormatter
  • Symfony\Component\Console\Helper\ProgressBar
  • Symfony\Component\Console\Helper\QuestionHelper
  • Symfony\Component\Console\Cursor
Environment
php
Created
2026-08-16T14:03:33Z

Contract

  1. StreamOutput does not close its underlying stream resource when destroyed, leaving the file descriptor open unless explicitly closed with fclose by the caller
  2. ConsoleOutput caches its stdout and stderr streams in private static variables, sharing the identical stream resource across separate ConsoleOutput instances
  3. OutputFormatter retains unclosed tag styles on OutputFormatterStyleStack across separate format and write calls, propagating styles into subsequent messages until explicitly closed with </>
  4. QuestionHelper on encountering EOF from a StreamableInputInterface permanently sets isInteractive to false on the input instance, silently disabling interactive prompts for all subsequent questions
  5. ProgressBar instantiated with ConsoleOutputInterface writes progress output to getErrorOutput() (STDERR) instead of STDOUT, and ProgressBar::finish() omits a trailing newline
  6. BufferedOutput::fetch() destructively drains the internal buffer rather than caching it, returning an empty string on subsequent calls
  7. Cursor::hide() and Cursor::show() emit the ANSI sequences \x1b[?25l and \x1b[?25h\x1b[?0c without resetting cursor visibility upon command completion or object destruction

Files

  • NOTES.md
  • composer.json
  • composer.lock
  • csx.json
  • test/contract.php

Download the source artifact (tar.gz)

Source

NOTES.md
# Notes

## Search Results
`search_known_solution` returned candidate samples `sha256:14dd434489e1359c9763ff1d4b367d176e5e60de805649a7f09831dc5b572bc2` (Go SDK attribute merge), `sha256:19df5703d8dc81fc82d005c9a1da5e4e2cbf15e79f3bda3895e0373c83079fce` (OpenTelemetry slice truncation), and `sha256:e0ab881bb6e03a1d68177d32a6688b85505ae28037acb54405bac8d34cdf554c` (Go embed path formatting). This sample addresses a distinct angle: resource lifecycle, stream closure omissions in `StreamOutput`, process-wide stream caching in `ConsoleOutput`, style stack state retention across independent formatting calls in `OutputFormatter`, silent interactivity muting on EOF in `QuestionHelper`, and stderr stream routing in `ProgressBar`.

## What a Naive Model Would Write
A naive model expects that destroying a `StreamOutput` automatically closes its wrapped PHP stream resource, that instantiating `ConsoleOutput` opens separate, unshared stream descriptors, that `OutputFormatter` resets open ANSI style tags between separate `format()` calls, that `QuestionHelper` maintains stream interactivity across successive questions even after empty reads, and that `ProgressBar` writes progress feedback to standard output.

## How the Wrong Version Fails
Fails silently with leaked file descriptors when omitting explicit `fclose()`, cross-instance stream corruption if a cached `ConsoleOutput` handle is closed, persistent ANSI color code bleed into subsequent console output when tags are unclosed, silent suppression of interactive question prompts following an EOF read, and missing progress bar output when piping STDOUT.
composer.json
{
    "require": {
        "symfony/console": "^7.4"
    }
}
composer.lock
{
    "_readme": [
        "This file locks the dependencies of your project to a known state",
        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
        "This file is @generated automatically"
    ],
    "content-hash": "365120514db039d11645629eab431730",
    "packages": [
        {
            "name": "psr/container",
            "version": "2.0.2",
            "source": {
                "type": "git",
                "url": "https://github.com/php-fig/container.git",
                "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963",
                "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963",
                "shasum": ""
            },
            "require": {
                "php": ">=7.4.0"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "2.0.x-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "Psr\\Container\\": "src/"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "PHP-FIG",
                    "homepage": "https://www.php-fig.org/"
                }
            ],
            "description": "Common Container Interface (PHP FIG PSR-11)",
            "homepage": "https://github.com/php-fig/container",
            "keywords": [
                "PSR-11",
                "container",
                "container-interface",
                "container-interop",
                "psr"
            ],
            "support": {
                "issues": "https://github.com/php-fig/container/issues",
                "source": "https://github.com/php-fig/container/tree/2.0.2"
            },
            "time": "2021-11-05T16:47:00+00:00"
        },
        {
            "name": "symfony/console",
            "version": "v7.4.16",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/console.git",
                "reference": "f4c69c9aed03abf933b294257d618bdd9b30a06d"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/console/zipball/f4c69c9aed03abf933b294257d618bdd9b30a06d",
                "reference": "f4c69c9aed03abf933b294257d618bdd9b30a06d",
                "shasum": ""
            },
            "require": {
                "php": ">=8.2",
                "symfony/deprecation-contracts": "^2.5|^3",
                "symfony/polyfill-mbstring": "~1.0",
                "symfony/service-contracts": "^2.5|^3",
                "symfony/string": "^7.2|^8.0"
            },
            "conflict": {
                "symfony/dependency-injection": "<6.4",
                "symfony/dotenv": "<6.4",
                "symfony/event-dispatcher": "<6.4",
                "symfony/lock": "<6.4",
                "symfony/process": "<6.4"
            },
            "provide": {
                "psr/log-implementation": "1.0|2.0|3.0"
            },
            "require-dev": {
                "psr/log": "^1|^2|^3",
                "symfony/config": "^6.4|^7.0|^8.0",
                "symfony/dependency-injection": "^6.4|^7.0|^8.0",
                "symfony/event-dispatcher": "^6.4|^7.0|^8.0",
                "symfony/http-foundation": "^6.4|^7.0|^8.0",
                "symfony/http-kernel": "^6.4|^7.0|^8.0",
                "symfony/lock": "^6.4|^7.0|^8.0",
                "symfony/messenger": "^6.4|^7.0|^8.0",
                "symfony/process": "^6.4|^7.0|^8.0",
                "symfony/stopwatch": "^6.4|^7.0|^8.0",
                "symfony/var-dumper": "^6.4|^7.0|^8.0"
            },
            "type": "library",
            "autoload": {
                "psr-4": {
                    "Symfony\\Component\\Console\\": ""
                },
                "exclude-from-classmap": [
                    "/Tests/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Fabien Potencier",
                    "email": "fabien@symfony.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Eases the creation of beautiful and testable command line interfaces",
            "homepage": "https://symfony.com",
            "keywords": [
                "cli",
                "command-line",
                "console",
                "terminal"
            ],
            "support": {
                "source": "https://github.com/symfony/console/tree/v7.4.16"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2026-07-31T12:37:14+00:00"
        },
        {
            "name": "symfony/deprecation-contracts",
            "version": "v3.7.1",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/deprecation-contracts.git",
                "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d",
                "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d",
                "shasum": ""
            },
            "require": {
                "php": ">=8.1"
            },
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/contracts",
                    "name": "symfony/contracts"
                },
                "branch-alias": {
                    "dev-main": "3.7-dev"
                }
            },
            "autoload": {
                "files": [
                    "function.php"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "A generic function and convention to trigger deprecation notices",
            "homepage": "https://symfony.com",
            "support": {
                "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2026-06-05T06:23:12+00:00"
        },
        {
            "name": "symfony/polyfill-ctype",
            "version": "v1.37.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-ctype.git",
                "reference": "141046a8f9477948ff284fa65be2095baafb94f2"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/141046a8f9477948ff284fa65be2095baafb94f2",
                "reference": "141046a8f9477948ff284fa65be2095baafb94f2",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2"
            },
            "provide": {
                "ext-ctype": "*"
            },
            "suggest": {
                "ext-ctype": "For best performance"
            },
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "Symfony\\Polyfill\\Ctype\\": ""
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Gert de Pagter",
                    "email": "BackEndTea@gmail.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill for ctype functions",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "ctype",
                "polyfill",
                "portable"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-ctype/tree/v1.37.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2026-04-10T16:19:22+00:00"
        },
        {
            "name": "symfony/polyfill-intl-grapheme",
            "version": "v1.41.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
                "reference": "bb899c1db0aa8127dc3afe8cda4a67eb24915f8d"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/bb899c1db0aa8127dc3afe8cda4a67eb24915f8d",
                "reference": "bb899c1db0aa8127dc3afe8cda4a67eb24915f8d",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2"
            },
            "suggest": {
                "ext-intl": "For best performance"
            },
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill for intl's grapheme_* functions",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "grapheme",
                "intl",
                "polyfill",
                "portable",
                "shim"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.41.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2026-07-28T08:25:59+00:00"
        },
        {
            "name": "symfony/polyfill-intl-normalizer",
            "version": "v1.38.0",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
                "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/2d446c214bdbe5b71bde5011b060a05fece3ae6b",
                "reference": "2d446c214bdbe5b71bde5011b060a05fece3ae6b",
                "shasum": ""
            },
            "require": {
                "php": ">=7.2"
            },
            "suggest": {
                "ext-intl": "For best performance"
            },
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "Symfony\\Polyfill\\Intl\\Normalizer\\": ""
                },
                "classmap": [
                    "Resources/stubs"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill for intl's Normalizer class and related functions",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "intl",
                "normalizer",
                "polyfill",
                "portable",
                "shim"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.38.0"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2026-05-25T13:48:31+00:00"
        },
        {
            "name": "symfony/polyfill-mbstring",
            "version": "v1.38.2",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/polyfill-mbstring.git",
                "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6",
                "reference": "d3d318bad5e7a1bfbd026009c8bfb8d8f99ae6b6",
                "shasum": ""
            },
            "require": {
                "ext-iconv": "*",
                "php": ">=7.2"
            },
            "provide": {
                "ext-mbstring": "*"
            },
            "suggest": {
                "ext-mbstring": "For best performance"
            },
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/polyfill",
                    "name": "symfony/polyfill"
                }
            },
            "autoload": {
                "files": [
                    "bootstrap.php"
                ],
                "psr-4": {
                    "Symfony\\Polyfill\\Mbstring\\": ""
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Symfony polyfill for the Mbstring extension",
            "homepage": "https://symfony.com",
            "keywords": [
                "compatibility",
                "mbstring",
                "polyfill",
                "portable",
                "shim"
            ],
            "support": {
                "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.38.2"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2026-05-27T06:59:30+00:00"
        },
        {
            "name": "symfony/service-contracts",
            "version": "v3.7.1",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/service-contracts.git",
                "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/service-contracts/zipball/c0a284bab1ed8aa0417e3d69250ab437739563a0",
                "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0",
                "shasum": ""
            },
            "require": {
                "php": ">=8.1",
                "psr/container": "^1.1|^2.0",
                "symfony/deprecation-contracts": "^2.5|^3"
            },
            "conflict": {
                "ext-psr": "<1.1|>=2"
            },
            "type": "library",
            "extra": {
                "thanks": {
                    "url": "https://github.com/symfony/contracts",
                    "name": "symfony/contracts"
                },
                "branch-alias": {
                    "dev-main": "3.7-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "Symfony\\Contracts\\Service\\": ""
                },
                "exclude-from-classmap": [
                    "/Test/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Generic abstractions related to writing services",
            "homepage": "https://symfony.com",
            "keywords": [
                "abstractions",
                "contracts",
                "decoupling",
                "interfaces",
                "interoperability",
                "standards"
            ],
            "support": {
                "source": "https://github.com/symfony/service-contracts/tree/v3.7.1"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2026-06-16T09:55:08+00:00"
        },
        {
            "name": "symfony/string",
            "version": "v8.1.2",
            "source": {
                "type": "git",
                "url": "https://github.com/symfony/string.git",
                "reference": "286a76b7255e5cc4bf0101a0bc5388ecf1c38ccc"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/symfony/string/zipball/286a76b7255e5cc4bf0101a0bc5388ecf1c38ccc",
                "reference": "286a76b7255e5cc4bf0101a0bc5388ecf1c38ccc",
                "shasum": ""
            },
            "require": {
                "php": ">=8.4.1",
                "symfony/polyfill-ctype": "^1.8",
                "symfony/polyfill-intl-grapheme": "^1.33",
                "symfony/polyfill-intl-normalizer": "^1.0",
                "symfony/polyfill-mbstring": "^1.0"
            },
            "conflict": {
                "symfony/translation-contracts": "<2.5"
            },
            "require-dev": {
                "symfony/emoji": "^7.4|^8.0",
                "symfony/http-client": "^7.4|^8.0",
                "symfony/intl": "^7.4|^8.0",
                "symfony/translation-contracts": "^2.5|^3.0",
                "symfony/var-exporter": "^7.4|^8.0"
            },
            "type": "library",
            "autoload": {
                "files": [
                    "Resources/functions.php"
                ],
                "psr-4": {
                    "Symfony\\Component\\String\\": ""
                },
                "exclude-from-classmap": [
                    "/Tests/"
                ]
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Nicolas Grekas",
                    "email": "p@tchwork.com"
                },
                {
                    "name": "Symfony Community",
                    "homepage": "https://symfony.com/contributors"
                }
            ],
            "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way",
            "homepage": "https://symfony.com",
            "keywords": [
                "grapheme",
                "i18n",
                "string",
                "unicode",
                "utf-8",
                "utf8"
            ],
            "support": {
                "source": "https://github.com/symfony/string/tree/v8.1.2"
            },
            "funding": [
                {
                    "url": "https://symfony.com/sponsor",
                    "type": "custom"
                },
                {
                    "url": "https://github.com/fabpot",
                    "type": "github"
                },
                {
                    "url": "https://github.com/nicolas-grekas",
                    "type": "github"
                },
                {
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
                    "type": "tidelift"
                }
            ],
            "time": "2026-07-28T07:35:25+00:00"
        }
    ],
    "packages-dev": [],
    "aliases": [],
    "minimum-stability": "stable",
    "stability-flags": {},
    "prefer-stable": false,
    "prefer-lowest": false,
    "platform": {},
    "platform-dev": {},
    "plugin-api-version": "2.9.0"
}
csx.json
{"case":{"believed":"A model expects that destroying StreamOutput closes its underlying stream resource, ConsoleOutput opens fresh stream handles per instance, OutputFormatter resets style tags between format calls, and ProgressBar writes output to STDOUT.","caseId":"case:sha256:1baa5f4c60e78c8b1ff9bb4347c15c799ea9b2b841fcadff4332d0f3fc47556d","contract":["StreamOutput does not close its underlying stream resource when destroyed, leaving the file descriptor open unless explicitly closed with fclose by the caller","ConsoleOutput caches its stdout and stderr streams in private static variables, sharing the identical stream resource across separate ConsoleOutput instances","OutputFormatter retains unclosed tag styles on OutputFormatterStyleStack across separate format and write calls, propagating styles into subsequent messages until explicitly closed with \u003c/\u003e","QuestionHelper on encountering EOF from a StreamableInputInterface permanently sets isInteractive to false on the input instance, silently disabling interactive prompts for all subsequent questions","ProgressBar instantiated with ConsoleOutputInterface writes progress output to getErrorOutput() (STDERR) instead of STDOUT, and ProgressBar::finish() omits a trailing newline","BufferedOutput::fetch() destructively drains the internal buffer rather than caching it, returning an empty string on subsequent calls","Cursor::hide() and Cursor::show() emit the ANSI sequences \\x1b[?25l and \\x1b[?25h\\x1b[?0c without resetting cursor visibility upon command completion or object destruction"],"goal":"Handle unmanaged stream descriptors in StreamOutput, static stream caching in ConsoleOutput, unclosed style leaks in OutputFormatter, EOF interactivity muting in QuestionHelper, and stderr routing in ProgressBar","kind":"HOW","packages":["pkg:composer/symfony/console@7.4.16"],"schemaVersion":1,"symbols":["Symfony\\Component\\Console\\Output\\StreamOutput","Symfony\\Component\\Console\\Output\\ConsoleOutput","Symfony\\Component\\Console\\Output\\BufferedOutput","Symfony\\Component\\Console\\Formatter\\OutputFormatter","Symfony\\Component\\Console\\Helper\\ProgressBar","Symfony\\Component\\Console\\Helper\\QuestionHelper","Symfony\\Component\\Console\\Cursor"]},"contractCommand":["php","test/contract.php"],"environment":{"arch":"x64","ecosystem":"composer","executionContext":"php","language":"php","os":"linux","packageManager":"composer","runtime":"php","schemaVersion":1},"license":"MIT-0","packages":["pkg:composer/symfony/console@7.4.16"],"schemaVersion":1,"symbols":["Symfony\\Component\\Console\\Output\\StreamOutput","Symfony\\Component\\Console\\Output\\ConsoleOutput","Symfony\\Component\\Console\\Output\\BufferedOutput","Symfony\\Component\\Console\\Formatter\\OutputFormatter","Symfony\\Component\\Console\\Helper\\ProgressBar","Symfony\\Component\\Console\\Helper\\QuestionHelper","Symfony\\Component\\Console\\Cursor"],"verifierAdapter":"composer@1"}
test/contract.php
<?php

declare(strict_types=1);

require __DIR__ . '/../vendor/autoload.php';

use Symfony\Component\Console\Cursor;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\StreamOutput;
use Symfony\Component\Console\Question\Question;

// -----------------------------------------------------------------------------
// Contract 1: StreamOutput does not close its underlying stream resource when
// destroyed, leaving the file descriptor open unless explicitly closed with
// fclose by the caller
// -----------------------------------------------------------------------------
$streamHandle = fopen('php://memory', 'r+');
assert(is_resource($streamHandle), 'Precondition: streamHandle must be a valid resource');

$streamOutput = new StreamOutput($streamHandle);
$streamOutput->write('buffered data');

// Destroy the StreamOutput instance
unset($streamOutput);

assert(
    is_resource($streamHandle),
    'Contract 1 failed: StreamOutput destructor must leave the underlying stream open'
);
assert(
    'stream' === get_resource_type($streamHandle),
    'Contract 1 failed: Stream handle must retain active stream resource type'
);

// Explicit caller cleanup
fclose($streamHandle);
assert(
    !is_resource($streamHandle),
    'Contract 1 failed: Stream must be closed only after explicit fclose by caller'
);

// -----------------------------------------------------------------------------
// Contract 2: ConsoleOutput caches its stdout and stderr streams in private
// static variables, sharing the identical stream resource across separate
// ConsoleOutput instances
// -----------------------------------------------------------------------------
$consoleOutput1 = new ConsoleOutput();
$consoleOutput2 = new ConsoleOutput();

$stdoutResource1 = $consoleOutput1->getStream();
$stdoutResource2 = $consoleOutput2->getStream();

assert(
    $stdoutResource1 === $stdoutResource2,
    'Contract 2 failed: ConsoleOutput must reuse cached static stream resource across instances'
);

$stderrResource1 = $consoleOutput1->getErrorOutput()->getStream();
$stderrResource2 = $consoleOutput2->getErrorOutput()->getStream();

assert(
    $stderrResource1 === $stderrResource2,
    'Contract 2 failed: ConsoleOutput error stream must reuse cached static error resource across instances'
);
assert(
    $stdoutResource1 !== $stderrResource1,
    'Contract 2 failed: ConsoleOutput stdout and stderr must use distinct stream descriptors'
);

// -----------------------------------------------------------------------------
// Contract 3: OutputFormatter retains unclosed tag styles on OutputFormatterStyleStack
// across separate format and write calls, propagating styles into subsequent messages
// until explicitly closed with </>
// -----------------------------------------------------------------------------
$formatter = new OutputFormatter(true);
$formattedChunk1 = $formatter->format('<info>Unclosed step heading');
$formattedChunk2 = $formatter->format('Next line without tags');

// First chunk opens green style (\033[32m) and emits trailing reset
assert(
    str_starts_with($formattedChunk1, "\033[32m"),
    'Contract 3 failed: Chunk 1 must be styled with info green escape code'
);

// Second chunk inherits info style because style stack retained unclosed <info>
assert(
    str_starts_with($formattedChunk2, "\033[32m"),
    'Contract 3 failed: Chunk 2 must inherit unclosed info style from formatter style stack'
);
assert(
    str_contains($formatter->getStyleStack()->getCurrent()->apply('test'), "\033[32m"),
    'Contract 3 failed: Formatter style stack must retain active green style'
);

// Explicit closing tag resets stack
$formattedChunk3 = $formatter->format('</>Final plain text');
$formattedChunk4 = $formatter->format('Subsequent independent text');

assert(
    !str_contains($formattedChunk4, "\033[32m"),
    'Contract 3 failed: Chunk 4 must not have green styling after closing tag pops stack'
);

// -----------------------------------------------------------------------------
// Contract 4: QuestionHelper on encountering EOF from a StreamableInputInterface
// permanently sets isInteractive to false on the input instance, silently
// disabling interactive prompts for all subsequent questions
// -----------------------------------------------------------------------------
$inputStream = fopen('php://memory', 'r+');
fwrite($inputStream, "alice\n");
rewind($inputStream);

$streamInput = new ArrayInput([]);
$streamInput->setStream($inputStream);
$streamInput->setInteractive(true);

$questionHelper = new QuestionHelper();
$promptOutput = new BufferedOutput();

// First question successfully reads line from stream
$answer1 = $questionHelper->ask($streamInput, $promptOutput, new Question('Name: '));
assert(
    $answer1 === 'alice',
    'Contract 4 failed: First question must read alice from stream'
);
assert(
    $streamInput->isInteractive() === true,
    'Contract 4 failed: Input must remain interactive while stream has data'
);

// Second question encounters EOF; fallback default is returned but interactivity is permanently muted
$answer2 = $questionHelper->ask($streamInput, $promptOutput, new Question('City: ', 'default_city'));
assert(
    $answer2 === 'default_city',
    'Contract 4 failed: Second question must return default on EOF'
);
assert(
    $streamInput->isInteractive() === false,
    'Contract 4 failed: QuestionHelper must set isInteractive to false on input upon EOF'
);

// Even if more data is appended to the stream, subsequent ask() immediately returns default without reading
fwrite($inputStream, "bob\n");
$answer3 = $questionHelper->ask($streamInput, $promptOutput, new Question('Nick: ', 'default_nick'));
assert(
    $answer3 === 'default_nick',
    'Contract 4 failed: Non-interactive input must bypass stream and immediately return default answer'
);

fclose($inputStream);

// -----------------------------------------------------------------------------
// Contract 5: ProgressBar instantiated with ConsoleOutputInterface writes
// progress output to getErrorOutput() (STDERR) instead of STDOUT, and
// ProgressBar::finish() omits a trailing newline
// -----------------------------------------------------------------------------
$stdoutMem = fopen('php://memory', 'r+');
$stderrMem = fopen('php://memory', 'r+');

$customConsoleOutput = new ConsoleOutput();
$refStderr = new \ReflectionProperty(ConsoleOutput::class, 'stderr');
$refStderr->setValue($customConsoleOutput, new StreamOutput($stderrMem));
$refStdout = new \ReflectionProperty(StreamOutput::class, 'stream');
$refStdout->setValue($customConsoleOutput, $stdoutMem);

$progressBar = new ProgressBar($customConsoleOutput, 10);
$progressBar->start();
$progressBar->advance(5);
$progressBar->finish();

rewind($stdoutMem);
rewind($stderrMem);

$stdoutContent = stream_get_contents($stdoutMem);
$stderrContent = stream_get_contents($stderrMem);

assert(
    $stdoutContent === '',
    'Contract 5 failed: ProgressBar on ConsoleOutputInterface must not write to STDOUT'
);
assert(
    $stderrContent !== '',
    'Contract 5 failed: ProgressBar on ConsoleOutputInterface must write to STDERR'
);
assert(
    !str_ends_with($stderrContent, "\n") && !str_ends_with($stderrContent, "\r\n"),
    'Contract 5 failed: ProgressBar::finish() must not write a trailing newline'
);

fclose($stdoutMem);
fclose($stderrMem);

// -----------------------------------------------------------------------------
// Contract 6: BufferedOutput::fetch() destructively drains the internal buffer
// rather than caching it, returning an empty string on subsequent calls
// -----------------------------------------------------------------------------
$bufferedOutput = new BufferedOutput();
$bufferedOutput->writeln('persistent audit line');

$firstFetch = $bufferedOutput->fetch();
$secondFetch = $bufferedOutput->fetch();

assert(
    str_starts_with($firstFetch, 'persistent audit line'),
    'Contract 6 failed: First fetch must return buffered content'
);
assert(
    $secondFetch === '',
    'Contract 6 failed: Second fetch must return empty string because fetch drains buffer'
);

// -----------------------------------------------------------------------------
// Contract 7: Cursor::hide() and Cursor::show() emit the ANSI sequences
// \x1b[?25l and \x1b[?25h\x1b[?0c without resetting cursor visibility upon
// command completion or object destruction
// -----------------------------------------------------------------------------
$cursorBuffer = new BufferedOutput();
$cursor = new Cursor($cursorBuffer);

$cursor->hide();
$hideSequence = $cursorBuffer->fetch();
assert(
    $hideSequence === "\x1b[?25l",
    'Contract 7 failed: Cursor::hide() must emit \x1b[?25l'
);

// Destroy cursor without calling show() - no automatic reset is emitted
unset($cursor);
$unmanagedBuffer = $cursorBuffer->fetch();
assert(
    $unmanagedBuffer === '',
    'Contract 7 failed: Cursor destructor must not automatically emit cursor restore escape sequence'
);

// Explicit show() emits restore sequence
$restoredCursor = new Cursor($cursorBuffer);
$restoredCursor->show();
$showSequence = $cursorBuffer->fetch();
assert(
    $showSequence === "\x1b[?25h\x1b[?0c",
    'Contract 7 failed: Cursor::show() must emit \x1b[?25h\x1b[?0c'
);

echo "OK: All symfony/console resource handling contracts verified.\n";

Origin Seeder

csx-seed