Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 43 additions & 15 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,6 @@ jobs:
- name: Run tests
run: npm test

- name: Prove architecture compiler (ADR sources only)
run: npm run test:integration

- name: Verify public-source release policy
run: npm run release:check

- name: Verify RECON self-documentation
run: |
npm run recon:self
echo "RECON self-documentation completed successfully"

portability:
name: OS portability / ${{ matrix.os }} / Node 24
runs-on: ${{ matrix.os }}
Expand Down Expand Up @@ -90,30 +79,69 @@ jobs:
- name: Run unit tests
run: npm test

- name: Prove architecture compiler
run: npm run test:integration
contract:
name: Contract qualification / Ubuntu / Node 22
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22.x
cache: npm
cache-dependency-path: package-lock.json

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.x'

- name: Install dependencies and repository hooks
run: npm ci

- name: Build
run: npm run build

- name: Lint
run: npm run lint

- name: Run contract guards
run: npm run test:contract-guards

- name: Prove architecture compiler
run: npm run test:integration

- name: Prove public tarball consumer
run: npm run test:public-tarball

- name: Verify public-source release policy
run: npm run release:check

- name: Verify RECON self-documentation
run: npm run recon:self

required:
name: required
if: ${{ always() }}
needs:
- test
- portability
- contract
runs-on: ubuntu-latest
steps:
- name: Verify mandatory test jobs succeeded
env:
TEST_RESULT: ${{ needs.test.result }}
PORTABILITY_RESULT: ${{ needs.portability.result }}
CONTRACT_RESULT: ${{ needs.contract.result }}
run: |
if [ "$TEST_RESULT" != "success" ] || [ "$PORTABILITY_RESULT" != "success" ]; then
echo "Required test gate failed: test=$TEST_RESULT portability=$PORTABILITY_RESULT"
if [ "$TEST_RESULT" != "success" ] || [ "$PORTABILITY_RESULT" != "success" ] || [ "$CONTRACT_RESULT" != "success" ]; then
echo "Required test gate failed: test=$TEST_RESULT portability=$PORTABILITY_RESULT contract=$CONTRACT_RESULT"
exit 1
fi

30 changes: 16 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,24 +185,26 @@ before connecting an editor.

## Programmatic Use

After building a source checkout, the current implementation exports can be
imported from `dist/index.js`:
The supported package-root API is the P1 runtime contract:

```js
import { initRssContext, search, blastRadius } from './dist/index.js';

const ctx = await initRssContext('.ste/state');
const matches = search(ctx, 'authentication');
const impact = matches.nodes[0]
? blastRadius(ctx, matches.nodes[0].key)
: { nodes: [] };

console.log({ matches: matches.nodes.length, impact: impact.nodes.length });
import { createRuntime } from './dist/index.js';

const runtime = createRuntime();
try {
const registration = await runtime.createRegistration({
repositories: [{ source: { kind: 'local', path: '/absolute/path/to/repository' } }],
});
const snapshot = await (await runtime.open(registration)).refresh();
console.log({ workspaceId: snapshot.workspaceId, nodes: snapshot.graph.nodes.length });
} finally {
await runtime.close();
}
```

This describes source-checkout use of current exports, not a production
package compatibility guarantee. See the verified
[RSS programmatic API guide](instructions/RSS-PROGRAMMATIC-API.md).
RSS remains a repository-internal/source-checkout API rather than a package-root
contract. Use the RSS CLI for supported RSS workflows; its internal APIs are
documented separately for repository maintainers.

## Architecture Records and Generated State

Expand Down
2 changes: 1 addition & 1 deletion adrs/index/architecture-index.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
schema_version: '1.1'
type: architecture_index
architecture_namespace: ste-runtime
generated_at: '2026-08-13T00:43:39Z'
generated_at: '2026-08-14T02:09:04Z'
generator: adr-architecture-index
entity_registry_path: adrs/index/entity-registry.yaml
relationship_registry_path: adrs/index/relationship-registry.yaml
Expand Down
9 changes: 5 additions & 4 deletions adrs/index/entity-registry.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5588,8 +5588,8 @@ entities:
entity_type: invariant
name: 019ff84e-4ece-7387-b33f-3d203e3c968c
summary: >-
Single repository only: RECON discovers files within the current repository. Cross-repository reconciliation is
out of scope.
RECON extraction is repository-local: each repository observation discovers files within its registered repository
source. Workspace orchestration may compose multiple repository observations into one derived workspace p
lifecycle_stage: active
admission_status: admitted
canonical_source:
Expand All @@ -5601,8 +5601,9 @@ entities:
adr_id: 019ff84e-4ece-791b-822f-21f537c95340
scope: global
statement: >-
Single repository only: RECON discovers files within the current repository. Cross-repository reconciliation is
out of scope.
RECON extraction is repository-local: each repository observation discovers files within its registered
repository source. Workspace orchestration may compose multiple repository observations into one derived
workspace projection. Cross-workspace reconciliation remains out of scope unless explicitly federated.
enforcement_level: must
declaration_mode: local
upheld_by_decisions: []
Expand Down
9 changes: 5 additions & 4 deletions adrs/index/invariant-registry.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,8 @@ entities:
entity_type: invariant
name: 019ff84e-4ece-7387-b33f-3d203e3c968c
summary: >-
Single repository only: RECON discovers files within the current repository. Cross-repository reconciliation is
out of scope.
RECON extraction is repository-local: each repository observation discovers files within its registered repository
source. Workspace orchestration may compose multiple repository observations into one derived workspace p
lifecycle_stage: active
admission_status: admitted
canonical_source:
Expand All @@ -237,8 +237,9 @@ entities:
adr_id: 019ff84e-4ece-791b-822f-21f537c95340
scope: global
statement: >-
Single repository only: RECON discovers files within the current repository. Cross-repository reconciliation is
out of scope.
RECON extraction is repository-local: each repository observation discovers files within its registered
repository source. Workspace orchestration may compose multiple repository observations into one derived
workspace projection. Cross-workspace reconciliation remains out of scope unless explicitly federated.
enforcement_level: must
declaration_mode: local
upheld_by_decisions: []
Expand Down
2 changes: 1 addition & 1 deletion adrs/manifest.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
schema_version: '1.0'
type: manifest
generated_date: '2026-08-13T00:43:39Z'
generated_date: '2026-08-14T02:09:04Z'
generated_from: adrs/**/*.yaml
adrs:
- id: 019ff84e-4ece-70ba-bf2e-a0fecd4a986e
Expand Down
18 changes: 11 additions & 7 deletions instructions/RSS-PROGRAMMATIC-API.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ checkout use; the package remains private and unpublished.

### Installation

The RSS API is exported from the built source checkout. After `npm ci` and
`npm run build`, local code may import from `./dist/index.js` or use a local
`npm link`. Do not use `npm install ste-runtime`; the package is not published.
RSS is a repository-internal/source-checkout API. It is not exported from the
`ste-runtime` package root, which exposes the public runtime contract only.
After `npm ci` and `npm run build`, repository-maintainer scripts may import
the built internal module below. Do not use `npm install ste-runtime`; the
package is not published.

```typescript
import {
Expand Down Expand Up @@ -61,13 +63,14 @@ import {
type RssQueryResult,
type BrokenEdge,
type BidirectionalInconsistency,
} from './dist/index.js';
} from './dist/rss/rss-operations.js';
```

For TypeScript tooling, importing directly from the source is also possible:
For source-level TypeScript tooling inside this repository, importing directly
from the internal module is also possible:

```typescript
import { initRssContext, search } from './ste-runtime/src/rss/rss-operations.js';
import { initRssContext, search } from './src/rss/rss-operations.js';
```

### Basic Usage
Expand Down Expand Up @@ -565,7 +568,8 @@ Complete understanding without misses
### Implementation Pattern

```typescript
import { initRssContext, findEntryPoints, blastRadius } from 'ste-runtime';
// Repository-internal API; not a package-root import.
import { initRssContext, findEntryPoints, blastRadius } from './dist/rss/rss-operations.js';

async function getRelevantFiles(task: string): Promise<string[]> {
const ctx = await initRssContext('.ste/state');
Expand Down
28 changes: 28 additions & 0 deletions src/public/runtime.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,4 +330,32 @@ describe('no-source current projection', () => {
await fs.rm(repositoryB, { recursive: true, force: true });
}
});

it('isolates concurrent refreshes without materializing state in either source repository', async () => {
const repositoryA = await createFixtureRepository('ste-runtime-concurrent-a');
const repositoryB = await createFixtureRepository('ste-runtime-concurrent-b');
const runtime = createRuntime();
try {
const [registrationA, registrationB] = await Promise.all([
runtime.createRegistration({ repositories: [{ source: { kind: 'local', path: repositoryA } }] }),
runtime.createRegistration({ repositories: [{ source: { kind: 'local', path: repositoryB } }] }),
]);
const [snapshotA, snapshotB] = await Promise.all([
(await runtime.open(registrationA)).refresh(),
(await runtime.open(registrationB)).refresh(),
]);

expect(snapshotA.workspaceId).toBe(registrationA.workspaceId);
expect(snapshotB.workspaceId).toBe(registrationB.workspaceId);
expect(snapshotA.workspaceId).not.toBe(snapshotB.workspaceId);
for (const repository of [repositoryA, repositoryB]) {
await expect(fs.access(path.join(repository, '.ste'))).rejects.toMatchObject({ code: 'ENOENT' });
await expect(fs.access(path.join(repository, '.workspace-graph'))).rejects.toMatchObject({ code: 'ENOENT' });
}
} finally {
await runtime.close();
await fs.rm(repositoryA, { recursive: true, force: true });
await fs.rm(repositoryB, { recursive: true, force: true });
}
});
});
Loading
Loading