* chore: add an ASF source-header policy and audit it in the release gate The first Apache Maka (Incubating) source release has to apply the ASF header policy and enforce it, and nothing in the repository decided which files the policy covers or checked that they comply. `scripts/asf-license-headers.mjs` is that decision. It asserts two properties of the tree it is pointed at, and nothing else. Every entry is classified exactly once: covered by a comment syntax and required to carry the ASF header, or matched by one reviewed exclusion rule that records why the header does not belong there. And in every covered file the license text occurs exactly once, as the canonical rendering at the top. A file that is neither covered nor excluded fails the audit, so a new file type or an unexpected path cannot reach a release candidate until someone writes down which of the two it is. Both properties are stated about the artifact rather than about what the writer emits. An audit that asks "does this file start with the bytes I would write?" can only confirm its own writer: it treats a header rendering it does not recognize as absent, writes a second license block above it, and then accepts the result, because the block it just wrote is at the top of the file. So detection is deliberately loose and acceptance deliberately strict. Detection flattens comment punctuation and line wrapping away and finds the license text written with `//`, in a JSDoc block, with `#`, inside an HTML comment, at any indentation, with an `https` license URL, or rewrapped into a paragraph. Acceptance takes only the exact canonical rendering. `write` is correspondingly dumb: it inserts a header where there is none and refuses every other state, because reconciling someone else's rendering is a decision, not a rewrite. Nothing is dropped from the tree under audit. An extracted candidate is walked whole, with no directory skipped by name, because a file inside a `dist/` or `release/` directory in a source release is not a tree to audit around — it is unclassified, and the gate says so. An entry that is neither a directory nor a regular file is reported rather than passed over. What the enumeration does decide is which tree a checkout stands in for: the files a source release would carry, which means subtracting what `export-ignore` prunes. `.gitattributes` owns that fact, so the audit asks Git for it rather than restating it in a rule. A copy would answer for the original in the one case that matters — an extracted candidate containing such a path would be excused by the very reason that says it cannot be there. Asking Git also has to walk the ancestors, since `export-ignore` on a directory prunes the subtree while `git check-attr` reports one path at a time and does not inherit. The two modes now audit the same set of files. An exclusion rule names the files it excludes or states a structural property that holds for anything it matches. A bare directory prefix does neither: it lends its justification to whatever is added to that directory next. The rules cover the ASF release documents themselves, verbatim upstream license texts, the notices Maka publishes about a bundled third-party runtime, third-party work kept under its own license, generated files that a `check:` script byte-compares against a fresh run, payloads republished verbatim as prompt text or as a pull request body, byte-significant fixtures, formats with no comment syntax, binaries, and version-control metadata. ASF policy treats the part of a file that the copyright owner did not contribute as third-party work, so the files Maka adapted from opencode and from the Vercel AI SDK are excluded rather than given a whole-file header. Whether a heavily modified file should carry a combined header is a PPMC decision. Their attribution belongs to LICENSE and the NOTICE audit. The audit cannot determine provenance — that is a fact about people, not a property of a path — so it refuses to let an unreviewed claim of one pass. A covered file carrying an SPDX identifier, an explicit copyright line, or an adaptation notice fails unless it is recorded in `reviewedProvenance` with the decision that put an ASF header on it anyway. The markers were chosen by measuring them against the whole tree: those three hit three files between them, while `derived from` hits seventy and `opencode` hits forty-five, because Maka supports it as a provider. A net that noisy gets answered with a list of paths added to quiet it. This is a net and not a proof: it catches a file that states its origin, not prose that alludes to one. `scripts/protocol-epoch-check.mjs` gains one exemption. It requires an epoch bump whenever a file under the protocol directory changes, a conservative proxy for "the protocol changed" that is right to be conservative: a needless bump costs a number, a missed one ships two incompatible protocols under one. But inserting a license header provably does not change the protocol, and bumping for it would tell every peer the wire is incompatible over a comment. The guard now exempts a change that is exactly `applyHeader` applied to the previous content — the same authority that writes the headers, so the exemption covers the canonical insertion and nothing that merely resembles it. A protocol file that gained a header and a real edit fails that comparison and still needs an epoch. `Prepare ASF source candidate` runs the audit inside the extracted archive before anything installs or builds into that tree, so the release gate reads the exact bytes a voter downloads instead of a checkout that resembles them. CI runs it unconditionally beside the other install-free checks, because a header gate that only sees the affected surfaces is not a gate. Apache RAT was the alternative. It would put a JVM and a downloaded jar into the audit path that reviewers are expected to reproduce, and its glob exclusions fail open: a new unexpected file inside an excluded directory is approved silently. This audit needs no toolchain beyond the Node the archive already requires, and an unexpected file fails it. The headers themselves are not in this commit. Until the sweep lands, the audit reports every existing source file as missing one. Refs #3271 Generated-by: Claude Code * chore: apply the ASF license header to every covered source file `npm run write:asf-headers` produced this commit, and `npm run check:asf-headers` now passes on the checkout and on the extracted source archive. Every file in the header sweep is exactly its previous content with the standard ASF header inserted at the top, below an interpreter shebang, an HTML doctype, or Markdown front matter where one of those has to open the file. The two files described below, `DISCLAIMER-WIP` and `.git-blame-ignore-revs`, are the only hand edits in this commit; nothing else was touched by hand. `.asf.yaml`, which already carried the header, is untouched. `DISCLAIMER-WIP` no longer discloses that source files lack Apache license headers, because they no longer do. The remaining disclosures about `NOTICE` and about the software grant and ICLAs are unchanged and still open. `.git-blame-ignore-revs` gets an entry for this sweep. Following the convention the file documents, the placeholder records the landed hash in a follow-up right after the squash-merge, since a hash that never reaches main makes `git blame` fail outright. Merging this will require open pull requests to rebase. That is the cost of doing the sweep once; splitting it per directory would multiply the rebases instead of avoiding them. Refs #3271 Generated-by: Claude Code
5.9 KiB
Runtime v2 implementation notes
Archived on 2026-07-13. These notes describe the initial Phase 1–4 skeleton; the backend architecture chapters and current source now describe the active runtime.
Status: Phase 1–4 skeleton landed (compile-safe, tested). The production
SessionManager.sendMessage hot path is unchanged; the v2 seam exists
in parallel so future work can migrate onto it incrementally.
Source plan: docs/archive/runtime-v2-architecture-evolution.md.
What landed
Core contract (@maka/core)
packages/core/src/runtime-event.ts— the canonicalRuntimeEventfact model (role / author / status enums, content discriminated union, actions, refs, pure helpersisTerminalRuntimeEvent/runtimeEventHasModelVisibleContent/createRuntimeEventId).packages/core/src/__tests__/runtime-event.test.ts— focused contract tests.- New subpath export
@maka/core/runtime-event. The later public-API cleanup removed the package root barrel, so this subpath is now the only public route.
Runtime v2 seam (@maka/runtime)
Five new modules, each importable via its canonical subpath AND re-exported (selectively) from the runtime barrel:
| Module | Subpath | Role |
|---|---|---|
model-history.ts |
@maka/runtime/model-history |
Policy-driven buildModelHistoryFromRuntimeEvents() replacing ad-hoc StoredMessage filtering. |
invocation-context.ts |
@maka/runtime/invocation-context |
InvocationRequest / InvocationContext spine, injectable newId/now providers, InvocationResult envelope. |
runtime-runner.ts |
@maka/runtime/runtime-runner |
RuntimeRunner.run() collecting shell: preflight gate → context → user event → flow dispatch → terminal collection. |
agent-flow.ts |
@maka/runtime/agent-flow |
Formal AgentFlow / AgentFlowControl / FlowInput seam. |
ai-sdk-flow.ts |
@maka/runtime/ai-sdk-flow |
AiSdkFlow wrapping an AgentBackend; mapSessionEventToRuntimeEvent() placeholder mapping. |
Each module shipped with co-located tests for the initial migration seam.
Exports consolidated by the steward
packages/core/package.json— added"./runtime-event".packages/runtime/package.json— added the runtime-v2 subpath exports.- The later public-API cleanup removed both package root barrels in favor of explicit domain subpaths.
Reconciled: single InvocationContext type
InvocationContext is now owned by invocation-context.ts and reused by the
formal flow seam:
invocation-context.ts— the canonical runner/flow spine (requiredsource,startedAt,request,newId,now).agent-flow.ts— imports and re-exports that canonical type for theAgentFlow.run(ctx, input)contract.
The runtime barrel re-exports the canonical InvocationContext from
invocation-context.ts; the previous duplicate flow-local context was removed
so runner and flow code share the same identity/provider spine.
What remains (by phase)
- Phase 5 — Tool-event actions: promote
tool_output_delta/tool_progressSessionEvents to a dedicated tool-progress runtime action (currently partial tool-role heartbeats). RefinemapSessionEventToRuntimeEventrole/author policy. - Phase 6 — RuntimeGate: implement the real preflight (connection
readiness/rebind, blocked/running/waiting guards) behind
RuntimeGateand inject it into desktop + bot/gateway entrypoints. - Phase 7 — Projection: drive
StoredMessage/TurnRecord/SessionHeader/AgentRunStore/RunTrace/TelemetryRepowrites fromInvocationResult.events. WirebuildModelHistoryFromRuntimeEvents()into the liveAiSdkBackend.materializePriorMessagespath. - SessionManager delegation: replace the body of
SessionManager.sendMessagewithRuntimeRunner.run(...)behind a feature flag, mappingInvocationResult.events→ existingSessionEventprojection. A streamingasync *stream()variant may be added then if the renderer needs live deltas. TodayRuntimeRunner.run()is collecting (returnsPromise<InvocationResult>), not streaming. abort+completecoalescing:AiSdkFlowis a faithful translator (the backend emitsabortthen a trailingcomplete, and the flow emits both). Coalescing into a single terminal event is a runner/projection concern.- Flow runnable surface:
RuntimeRunnerdepends on the centrally ownedRunnableAgentFlow(Pick<AgentFlow, 'run'>) so it remains decoupled from flow metadata (kind,sessionId) while sharing the formalAgentFlow.runsignature.
Verification snapshot
All commands run from the repository root ($RIVE_WORKSPACE):
npm run build # all workspaces — clean
npm run typecheck # all workspaces — clean
npm --workspace @maka/core run test # 613 pass / 0 fail
npm --workspace @maka/runtime run test # 384 pass / 0 fail
git diff --check # clean
No production source (session-manager.ts, ai-sdk-backend.ts,
agent-run.ts, materializer.ts) was modified. The v2 seam is purely
additive.