From addc77e212e022cc630b16302ead78ea39fcdc35 Mon Sep 17 00:00:00 2001 From: tianxiaochannel-oss88 Date: Mon, 2 Nov 2026 20:10:08 +0800 Subject: [PATCH 1/2] docs: adopt TypeScript-first testing policy --- .github/PULL_REQUEST_TEMPLATE.md | 2 ++ AGENTS.md | 23 ++++++++++++++++++ CONTRIBUTING.md | 41 ++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 AGENTS.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b4b6b5627..796045d38 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -30,6 +30,8 @@ backward-compatibility impact. Write `None` only after checking each category. - [ ] The change is focused and follows existing module boundaries. - [ ] Tests cover the changed behavior or the missing coverage is explained. +- [ ] New or migrated tests follow the [testing policy](../CONTRIBUTING.md#testing-policy): TypeScript tests are executed and type-checked, or a concrete JavaScript exception is explained. +- [ ] Test consolidation or removal has supporting coverage and validation evidence; independent safety and architecture contracts remain protected. - [ ] Chinese and English product copy remain aligned when applicable. - [ ] Documentation and implementation status are updated when applicable. - [ ] No credentials, tokens, local databases, logs, artifacts, or private paths are committed. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..019e07927 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,23 @@ +# Ling Stack Agent Instructions + +## Testing + +Follow the [Testing Policy](CONTRIBUTING.md#testing-policy) for all new or changed tests. + +- Prefer TypeScript for new JavaScript/TypeScript-module tests and test helpers. + Ensure the owning runner discovers them and the package's validation commands and + relevant CI gates type-check them. File renames or runtime transpilation alone are + insufficient. Document concrete runtime or compatibility exceptions for JavaScript. +- Migrate existing `.mjs` tests incrementally when maintaining their owning module; + preserve coverage and test discovery, and avoid unrelated bulk conversions. +- Prefer behavior and boundary assertions over implementation-text matching. Preserve + independently valuable security, architecture, and other declared contract checks. +- Require evidence before consolidating or removing tests. Never delete tests to + reduce the JavaScript share or rewrite production code in Rust for that purpose. + +## Validation + +Run the narrowest relevant tests and the owning package's typecheck for test changes. +For documentation-only changes, use the checks in +[Contributing: Validation](CONTRIBUTING.md#validation). Report checks actually run and +any platform or runtime acceptance that remains unverified. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5f4e76f63..427ca43e4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -108,6 +108,47 @@ only when its description is complete and its claimed validation has actually ru states and theme switching. Include current screenshots; distinguish token integration, behavior verification and visual approval. +## Testing Policy + +### TypeScript By Default + +- For JavaScript/TypeScript modules, write new tests and test helpers in TypeScript by + default, using `.test.ts` or the owning suite's `.spec.ts` convention. Use `.tsx` + when a test needs JSX. Native-language tests should use their own ecosystem's tools. +- New or migrated TypeScript tests must be discovered by the owning test runner and + included in its type-checking configuration. Wire any separate test typecheck into + the package's validation commands and relevant CI gates. Renaming a file, transpiling + it, or stripping types at runtime does not establish that it was type-checked. +- When a package currently runs only `.mjs` tests, add the minimal package-local + TypeScript execution and typecheck support with its first TypeScript test, preserving + existing coverage and test entrypoints. Keep the existing runner where practical; + a repository-wide framework replacement is not required. +- JavaScript exceptions need a concrete runtime, host, or compatibility constraint, + explained in the pull request or a short adjacent comment. An existing `.mjs`-only + test glob alone is not a reason to keep adding JavaScript tests. + +### Incremental Migration + +- Existing `.mjs` tests remain valid. Prefer migrating touched tests as their owning + module is maintained, with execution and type checking verified together. +- Keep migrations scoped to the module and behavior being changed. Do not perform + unrelated mass renames, lose test discovery, or reduce coverage during migration. + +### Behavior And Independent Contracts + +- Prefer tests that exercise observable behavior, invariants, and public boundaries. + A source keyword or call-name match alone does not prove runtime behavior or call + order. Prioritize improving these assertions when maintaining the owning module. +- Keep source-inspection tests when they independently guard a declared security, + architecture, protocol, package, release, or generated-output contract. Make the + protected contract clear; static evidence does not replace required runtime or + platform acceptance. +- Consolidate or remove tests only with evidence that they are redundant, obsolete, + or ineffective. Explain what each removed test protected, why its removal is safe, + and which retained coverage and focused validation support that conclusion. +- Do not optimize test counts or language percentages by deleting tests. A preference + for TypeScript tests is not a reason to rewrite production modules in Rust. + ## Validation For documentation-only changes: From 1f35840bb9055a165d6ca1dd4b84cd1973068fad Mon Sep 17 00:00:00 2001 From: tianxiaochannel-oss88 Date: Mon, 2 Nov 2026 23:16:22 +0800 Subject: [PATCH 2/2] test(daemon): use lightweight native command for history budgets --- packages/daemon/test/protected-host-staging.test.mjs | 3 ++- packages/daemon/test/support/protected-host-stage-fixture.mjs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/daemon/test/protected-host-staging.test.mjs b/packages/daemon/test/protected-host-staging.test.mjs index 4921eaf4d..ffa339082 100644 --- a/packages/daemon/test/protected-host-staging.test.mjs +++ b/packages/daemon/test/protected-host-staging.test.mjs @@ -191,7 +191,8 @@ test("unknown actual bootstrap bytes close registration/current Office only, wit }); test("more than 256 real ordinary commands and more than 64 closed stage lifetimes do not exhaust history budgets", native, async t => { - const f = createProtectedHostStageFixture(t), command = commandFor("process.exit(0)"); + // Exercise real native launches without rehashing and starting Node 258 times. + const f = createProtectedHostStageFixture(t), command = "true"; for (let i = 0; i < 258; i++) { const prepared = await f.runtime.prepare(f.input(command, f.current, "many-call-" + i)); await waitActor(prepared.spawn()); prepared.dispose(); diff --git a/packages/daemon/test/support/protected-host-stage-fixture.mjs b/packages/daemon/test/support/protected-host-stage-fixture.mjs index 46faae190..0f4ee1d50 100644 --- a/packages/daemon/test/support/protected-host-stage-fixture.mjs +++ b/packages/daemon/test/support/protected-host-stage-fixture.mjs @@ -26,7 +26,8 @@ export function createProtectedHostStageFixture(t, { registry: suppliedRegistry const stagePath = join(root, "stage"); mkdirSync(stagePath, { mode: 0o700 }); const store = createSqliteRunStore(cwd), arenas = [], stages = new Set(); const pin = path => ({ path: realpathSync(path), sha256: createHash("sha256").update(readFileSync(path)).digest("hex") }); - const config = { inputHelper: { ...pin("/usr/bin/true"), version: "stage-test-v1" }, executables: { node: pin(process.execPath) } }; + const config = { inputHelper: { ...pin("/usr/bin/true"), version: "stage-test-v1" }, + executables: { node: pin(process.execPath), true: pin("/usr/bin/true") } }; const supervisor = new RuntimeSupervisor(resolveConfig({ defaultWorkspaceCwd: cwd, sandbox: { restrictedCommands: config } })); // The real native cases use the production Supervisor's enrolled Registry. // Generic wrapper tests may supply their separate, initially unbound Registry