From 57d891fbd77b0e127afb12ba2acb8b45975bafb4 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Sat, 19 Sep 2026 12:29:17 +0900 Subject: [PATCH 1/2] Follow be-framework/be 0.x: #[SensitiveParameter] props masked in the semantic log Repin be-framework/be to 0.x-dev (60fd569, includes #78 semantic-logger-0.9 bump and #80 #[SensitiveParameter] masking) and bear/event-sourcing to 1.x-dev (e811a13, #26 tree.php fixes); koriym/semantic-logger stays pinned at 0.9.0. Verified with an observe login run: plaintext admin password occurrences in the semantic log dropped from 1 (leaking via becoming_open.prop) to 0, with [FILTERED] now masking both resource_request.params and becoming_open.prop. Re-synced .claude/skills/bear-observe/harness/tree.php from vendor/bear/event-sourcing; no other skill-dir diffs remain. --- .claude/skills/bear-observe/harness/tree.php | 73 ++++++++++++++++---- be/composer.json | 2 +- composer.json | 2 +- composer.lock | 29 ++++---- 4 files changed, 77 insertions(+), 29 deletions(-) diff --git a/.claude/skills/bear-observe/harness/tree.php b/.claude/skills/bear-observe/harness/tree.php index d38057e55..f59c898c4 100644 --- a/.claude/skills/bear-observe/harness/tree.php +++ b/.claude/skills/bear-observe/harness/tree.php @@ -6,22 +6,37 @@ /** * Renders an observation log as a tree, naming the type that closes each scope. * - * Usage: php tree.php [log.json] (default: the newest latest.json under var/log) + * Usage: php tree.php [log.json] [--full] (default: the newest latest.json under var/log) * * `stree` prints the closing context but not its type, and here the type carries the answer: * `get` closed by `cache_hit` and `get` closed by `cache_miss` have the same context keys. + * + * `--full` disables the 60-char value truncation; without it, a cut value is marked + * `...(+N)` with the number of characters dropped, so it reads as cut rather than as a + * value that happened to end there. */ $argvList = $argv; array_shift($argvList); +$full = false; +$positional = []; +foreach ((is_array($argvList) ? $argvList : []) as $arg) { + if ($arg === '--full') { + $full = true; + continue; + } + + $positional[] = $arg; +} + function fail(string $message): never { fwrite(STDERR, "FAIL {$message}\n"); exit(1); } -$file = $argvList[0] ?? null; +$file = $positional[0] ?? null; if ($file === null) { $found = glob(getcwd() . '/var/log/*/observe/latest.json') ?: []; $found !== [] || fail('no var/log/*/observe/latest.json — run a request first, or pass a path'); @@ -34,17 +49,47 @@ function fail(string $message): never is_array($log) || fail("not JSON: {$file}"); // Runs in the application's PHP, which may be a no-dev install without ext-mbstring. -function truncate(string $text): string +function truncate(string $text, bool $full): string { + if ($full) { + return $text; + } + if (function_exists('mb_substr')) { - return mb_strlen($text) > 60 ? mb_substr($text, 0, 57) . '...' : $text; + $length = mb_strlen($text); + + return $length > 60 ? mb_substr($text, 0, 57) . '...(+' . ($length - 57) . ')' : $text; + } + + $length = strlen($text); + + return $length > 60 ? substr($text, 0, 57) . '...(+' . ($length - 57) . ')' : $text; +} + +// A value whose whole string is backslash-joined identifiers is a FQCN, not a URI, a JSON +// blob, or free text — none of those parse as this pattern. +function shortenFqcn(string $text): string +{ + if (! str_contains($text, '\\') || preg_match('/^(\\\\?[A-Za-z_][A-Za-z0-9_]*)+$/', $text) !== 1) { + return $text; + } + + $pos = strrpos($text, '\\'); + + return $pos === false ? $text : substr($text, $pos + 1); +} + +function formatScalar(bool|int|float|string $value): string +{ + if (is_bool($value)) { + return $value ? 'true' : 'false'; } - return strlen($text) > 60 ? substr($text, 0, 57) . '...' : $text; + return (string) $value; } /** @param array $context */ -function summarize(array $context): string +function summarize(array $context, bool $full): string { $parts = []; foreach ($context as $key => $value) { @@ -52,19 +97,21 @@ function summarize(array $context): string continue; } - $text = is_scalar($value) ? (string) $value : (string) json_encode($value, JSON_UNESCAPED_SLASHES); + $text = is_scalar($value) ? formatScalar($value) : (string) json_encode($value, JSON_UNESCAPED_SLASHES); if ($key === 'body_ref') { $text = basename($text); + } elseif (is_string($value)) { + $text = shortenFqcn($text); } - $parts[] = $key . '=' . truncate($text); + $parts[] = $key . '=' . truncate($text, $full); } return implode(' ', $parts); } /** @param array $node */ -function render(array $node, string $indent = ''): void +function render(array $node, bool $full, string $indent = ''): void { // Events are recorded against the enclosing scope, so they belong under it, ahead of the // scopes it went on to open. @@ -80,12 +127,12 @@ function render(array $node, string $indent = ''): void $next = $indent . ($i === $last ? ' ' : '│ '); $close = $child['close'] ?? null; $arrow = is_array($close) && is_string($close['type'] ?? null) - ? ' → ' . $close['type'] . ' ' . summarize((array) ($close['context'] ?? [])) + ? ' → ' . $close['type'] . ' ' . summarize((array) ($close['context'] ?? []), $full) : ''; - echo $indent, $branch, $child['type'], ' ', summarize((array) ($child['context'] ?? [])), $arrow, "\n"; - render($child, $next); + echo $indent, $branch, $child['type'], ' ', summarize((array) ($child['context'] ?? []), $full), $arrow, "\n"; + render($child, $full, $next); } } echo $file, "\n"; -render($log); +render($log, $full); diff --git a/be/composer.json b/be/composer.json index 3c4a7769c..9997dcb30 100644 --- a/be/composer.json +++ b/be/composer.json @@ -5,7 +5,7 @@ "description": "BeMart Be — pure Be Framework domain (Input / Final / Semantic / Exception / Becoming / Reason) for the BeMart project.", "require": { "php": "^8.3", - "be-framework/be": "dev-semantic-logger-0.9 as 0.1.0", + "be-framework/be": "0.x-dev as 0.1.0", "ray/input-query": "^1.0", "ray/media-query": "^1.1" }, diff --git a/composer.json b/composer.json index c9078d51a..659ff8dee 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ ], "require": { "php": "^8.3", - "be-framework/be": "dev-semantic-logger-0.9 as 0.1.0", + "be-framework/be": "0.x-dev as 0.1.0", "bear/devtools": "dev-master", "bear/package": "^1.14", "bear/query-repository": "1.x-dev", diff --git a/composer.lock b/composer.lock index cba493e29..cb5374766 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f2d015bd9a2cfd9d5a3a1af24c60a709", + "content-hash": "6bcbec6c34b040019ca68b7803e304ad", "packages": [ { "name": "aura/cli", @@ -502,16 +502,16 @@ }, { "name": "be-framework/be", - "version": "dev-semantic-logger-0.9", + "version": "0.x-dev", "source": { "type": "git", "url": "https://github.com/be-framework/Be.Framework.git", - "reference": "d6ca6d263119b8a687d9daa7284b424c6f9f9395" + "reference": "60fd5690d2a83442d645c8f678894a3222d7eefd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/be-framework/Be.Framework/zipball/d6ca6d263119b8a687d9daa7284b424c6f9f9395", - "reference": "d6ca6d263119b8a687d9daa7284b424c6f9f9395", + "url": "https://api.github.com/repos/be-framework/Be.Framework/zipball/60fd5690d2a83442d645c8f678894a3222d7eefd", + "reference": "60fd5690d2a83442d645c8f678894a3222d7eefd", "shasum": "" }, "require": { @@ -530,6 +530,7 @@ "phpunit/phpunit": "^12.2", "vimeo/psalm": "^6.0@dev" }, + "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -553,9 +554,9 @@ "description": "Be Framework - The Ontological Programming Framework for PHP", "support": { "issues": "https://github.com/be-framework/Be.Framework/issues", - "source": "https://github.com/be-framework/Be.Framework/tree/semantic-logger-0.9" + "source": "https://github.com/be-framework/Be.Framework/tree/0.x" }, - "time": "2026-08-17T03:12:22+00:00" + "time": "2026-09-19T03:18:30+00:00" }, { "name": "bear/app-meta", @@ -2061,10 +2062,10 @@ "dist": { "type": "path", "url": "be", - "reference": "582b54fe20c555993e476620e427f520c37864e1" + "reference": "6cc39777e8ed27fb0e7b9f43fb420ca74888deec" }, "require": { - "be-framework/be": "dev-semantic-logger-0.9 as 0.1.0", + "be-framework/be": "0.x-dev as 0.1.0", "php": "^8.3", "ray/input-query": "^1.0", "ray/media-query": "^1.1" @@ -7292,12 +7293,12 @@ "source": { "type": "git", "url": "https://github.com/bearsunday/BEAR.EventSourcing.git", - "reference": "8616c825999227de2f7b065445082b177c479f01" + "reference": "e811a13a47c08f4795bcd223d31b7778a68ba30c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bearsunday/BEAR.EventSourcing/zipball/8616c825999227de2f7b065445082b177c479f01", - "reference": "8616c825999227de2f7b065445082b177c479f01", + "url": "https://api.github.com/repos/bearsunday/BEAR.EventSourcing/zipball/e811a13a47c08f4795bcd223d31b7778a68ba30c", + "reference": "e811a13a47c08f4795bcd223d31b7778a68ba30c", "shasum": "" }, "require": { @@ -7378,7 +7379,7 @@ "issues": "https://github.com/bearsunday/BEAR.EventSourcing/issues", "source": "https://github.com/bearsunday/BEAR.EventSourcing" }, - "time": "2026-09-17T09:48:05+00:00" + "time": "2026-09-19T03:17:37+00:00" }, { "name": "composer/pcre", @@ -9518,7 +9519,7 @@ "aliases": [ { "package": "be-framework/be", - "version": "dev-semantic-logger-0.9", + "version": "0.9999999.9999999.9999999-dev", "alias": "0.1.0", "alias_normalized": "0.1.0.0" }, From 78903cc14cb573155b769e2c54a3979fb51da223 Mon Sep 17 00:00:00 2001 From: Akihito Koriyama Date: Sat, 19 Sep 2026 12:42:35 +0900 Subject: [PATCH 2/2] =?UTF-8?q?be/composer.json=20=E3=82=92=202=20?= =?UTF-8?q?=E3=82=B9=E3=83=9A=E3=83=BC=E3=82=B9=E3=82=A4=E3=83=B3=E3=83=87?= =?UTF-8?q?=E3=83=B3=E3=83=88=E3=81=AB=E7=B5=B1=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AGENTS.md の JSON 規約に合わせる。内容は不変(jq -c で一致)。 path package の lock reference は内容由来なので追随して更新。 --- be/composer.json | 50 ++++++++++++++++++++++++------------------------ composer.lock | 2 +- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/be/composer.json b/be/composer.json index 9997dcb30..d18f566a1 100644 --- a/be/composer.json +++ b/be/composer.json @@ -1,28 +1,28 @@ { - "name": "my-vendor/be-mart-be", - "type": "library", - "license": "MIT", - "description": "BeMart Be — pure Be Framework domain (Input / Final / Semantic / Exception / Becoming / Reason) for the BeMart project.", - "require": { - "php": "^8.3", - "be-framework/be": "0.x-dev as 0.1.0", - "ray/input-query": "^1.0", - "ray/media-query": "^1.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0" - }, - "autoload": { - "psr-4": { - "MyVendor\\BeMart\\Be\\": "src/" - } - }, - "autoload-dev": { - "psr-4": { - "MyVendor\\BeMart\\Be\\Tests\\": "tests/" - } - }, - "config": { - "sort-packages": true + "name": "my-vendor/be-mart-be", + "type": "library", + "license": "MIT", + "description": "BeMart Be — pure Be Framework domain (Input / Final / Semantic / Exception / Becoming / Reason) for the BeMart project.", + "require": { + "php": "^8.3", + "be-framework/be": "0.x-dev as 0.1.0", + "ray/input-query": "^1.0", + "ray/media-query": "^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^10.0" + }, + "autoload": { + "psr-4": { + "MyVendor\\BeMart\\Be\\": "src/" } + }, + "autoload-dev": { + "psr-4": { + "MyVendor\\BeMart\\Be\\Tests\\": "tests/" + } + }, + "config": { + "sort-packages": true + } } diff --git a/composer.lock b/composer.lock index cb5374766..8e4171721 100644 --- a/composer.lock +++ b/composer.lock @@ -2062,7 +2062,7 @@ "dist": { "type": "path", "url": "be", - "reference": "6cc39777e8ed27fb0e7b9f43fb420ca74888deec" + "reference": "2af920313bc6a519e1c9e11346cbbfe54095528a" }, "require": { "be-framework/be": "0.x-dev as 0.1.0",