Skip to content

Add Request::withAttributes() — set several attributes in one instance - #7

Merged
hakeemRash merged 1 commit into
mainfrom
release-withattributes
Aug 29, 2026
Merged

Add Request::withAttributes() — set several attributes in one instance#7
hakeemRash merged 1 commit into
mainfrom
release-withattributes

Conversation

@hakeemRash

Copy link
Copy Markdown
Contributor

Every with*() deep-clones all seven Symfony parameter bags, so a chain of them pays that price once per link.

The kernel's ResolveStage attaches route_entry, route_params and target_service — one logical step that cost three full clones of a request nothing had read yet. withAttributes() does it in one.

Measured on the kernel's routing step: 10.02 µs → 3.57 µs (64% less), and ~2.2 KB less garbage per request.

Identical in effect to chaining withAttribute(); it just does not build the two intermediate requests that get thrown away. Immutability is unchanged — the original is untouched, and the kernel's RequestTest asserts the batched result is byte-identical to the chain it replaces. An empty array returns $this, since there is nothing to copy.

Required by hkm-kernel v1.6.0, which pins this commit as its modules/http submodule.

🤖 Generated with Claude Code

hakeemRash added a commit to AlfaCode-Team/hkm-kernel that referenced this pull request Aug 29, 2026
The pointer was d1b1366, which lived only in a local checkout on a detached
HEAD. Nothing could resolve it: `git submodule update --init` fails for a clone
and for CI, and `Kernel\Http\Request` never loads — while ResolveStage now calls
withAttributes(), which exists in no pushed commit at all. Releasing against
that pin would have shipped a kernel whose routing calls a method the published
http package does not have.
c4fe527 is the same change cherry-picked onto origin/main (AlfaCode-Team/http#7)
and pushed, so the pin resolves.
@hakeemRash
hakeemRash merged commit 8bb2173 into mainAug 29, 2026
1 check passed
hakeemRash added a commit to AlfaCode-Team/hkm-kernel that referenced this pull request Aug 29, 2026
…OOT_CACHE work (#124)
## Why
Four things in the kernel were documented as working and were not. Each
is a case where a declaration read as a guarantee and compiled to
nothing.
## The queue was not an authenticated channel
`WorkerLoop` has always carried a signature check, but the kernel had no
way to give it a key — `$signingSecret` defaulted to `''`, was never
passed at construction, and no builder method existed. **In every
deployment that has ever run, it was dead code and the worker executed
whatever it was handed.**
And the signature it would have checked covered `data` alone, leaving
`jobClass` — the field deciding *which code runs* — unauthenticated.
Capturing one legitimately signed envelope and swapping its class for
any other `JobContract` was enough; no forgery required.
`Kernel::withWorkerSecret()` makes the check reachable, and the material
is now `jobId | jobClass | queue | maxAttempts | canonical(data)`. Off
by default, and deliberately **not** falling back to `APP_KEY` — that
would switch verification on everywhere at once and reject every job in
flight.
A payload that failed verification used to return `skipped()`, which
`processWithPort` then **acked** — deleting the only evidence something
is writing to your queue. It now dead-letters through the
`ErrorPipeline`.
## BOOT_CACHE never hit
`build()` computed `buildHash()` twice, before and after
`resolveEssentialModules()` rewrites `essentials` from proj.json DOMAINS
into provider CLASSES. Written under one hash, read under another — so
every request recompiled all ten manifests *and* rewrote the stamp,
**worse than leaving the flag off**.
```
BOOT_CACHE on, essentials=domain: 2865 us -> 39 us (per request, PHP-FPM)
```
`BootStampTest` tests the stamp in isolation and could not see this;
`KernelBootCacheTest` builds twice through the real `Kernel::build()`
and watches the manifest inode.
## Also
- **No `pcntl` anywhere** — SIGTERM killed the worker mid-flight,
including between `handle()` returning and `ack()`, so a job that had
run its side effects came back and ran them again.
- **`retry`/`timeout` in `module.json` compiled to nothing** — every job
shared one hardcoded strategy.
- **Request clones** — `ResolveStage` 10.02 -> 3.57 us;
`SecurityGateway` 4.17 -> 0.87 us.
- **`hkm run` ignored its documented `./` default** — an `args.len <= 2`
guard fired before the resolver, which broke `hkm run --dev`
specifically (`--dev` is stripped before parsing, so it arrived as
exactly `["hkm","run"]`).
## Depends on
**AlfaCode-Team/http#7** — `ResolveStage` calls
`Request::withAttributes()`, which exists only there. The submodule is
pinned to `c4fe527` from that PR's branch. **If #7 is squash-merged the
SHA changes and this pin must be repointed before merging.**
## Verification
352 tests (from 312), PHPStan clean, launcher builds, and the dev server
serves 200 on both routes. Benchmarks re-measured, not recalled.
## Risk
Enabling job signing is a two-sided change: the `QueuePort` adapter must
stamp `JobPayload::signatureFor()` at `push()` time. Until it does,
every payload is rejected — correct, but roll it out producer-first. No
migration is needed for the algorithm change, since nothing signed
before.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@hakeemRash