-
Notifications
You must be signed in to change notification settings - Fork 14
test: close merged review coverage gaps #2597
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e6076a0
004acdd
33031fc
e2a18d5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,6 +44,14 @@ describe('entity-share recovery beside malformed KA heads', () => { | |
| publish([root, siblingRoot], [...payload, ...siblingPayload]), | ||
| publish([root], payload, 'research'), | ||
| ]); | ||
| const recoveryOrderedMeta = ( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Suggestion: Manifest ordering was removed from the shared publisher fixture and re-derived inside one consumer. Why it matters Suggestion |
||
| fixture: Awaited<ReturnType<typeof publish>>, | ||
| ): Quad[] => { | ||
| const sliceSubjects = fixture.slices.map((slice) => slice.sliceSubject); | ||
| return [...fixture.meta].sort( | ||
| (a, b) => sliceSubjects.indexOf(a.subject) - sliceSubjects.indexOf(b.subject), | ||
| ); | ||
| }; | ||
| const sliceFor = (fixture: Awaited<ReturnType<typeof publish>>, rootEntity: string) => { | ||
| const slice = fixture.slices.find(candidate => candidate.rootEntity === rootEntity); | ||
| if (!slice) throw new Error(`Entity-share recovery fixture did not publish ${rootEntity}`); | ||
|
|
@@ -61,9 +69,11 @@ describe('entity-share recovery beside malformed KA heads', () => { | |
| } | ||
| const metaGraph = entityPublished.metaGraph; | ||
| const namedMetaGraph = namedPublished.metaGraph; | ||
| const entityMeta = entityPublished.meta; | ||
| const twoRootMeta = twoRootPublished.meta; | ||
| const namedMeta = namedPublished.meta; | ||
| // Recovery traversal owns its deterministic manifest order; the publisher | ||
| // fixture returns the publisher/store result without consumer policy. | ||
| const entityMeta = recoveryOrderedMeta(entityPublished); | ||
| const twoRootMeta = recoveryOrderedMeta(twoRootPublished); | ||
| const namedMeta = recoveryOrderedMeta(namedPublished); | ||
| const sliceSubject = entitySlice.sliceSubject; | ||
| const siblingSubject = siblingSlice.sliceSubject; | ||
| const ka = swmFixtures(COVERAGE_CG).manifest(1)[0]!; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -67,19 +67,31 @@ describe('RFC-64 10.0.16 legacy SWM boundary', () => { | |
|
|
||
| it('captures once, remains private by count, and retires only after explicit republish', async () => { | ||
| const root = await secureTempRoot(roots); | ||
| const heads = new Map<string, string[]>([ | ||
| [META_GRAPH, [UAL_ONE]], | ||
| [SUBGRAPH_META_GRAPH, []], | ||
| ]); | ||
| const store = fakeStore(heads); | ||
| const store = new OxigraphStore(); | ||
| const listGraphs = vi.spyOn(store, 'listGraphs'); | ||
| await store.insert(legacySwmBoundaryFixtureQuadsV1({ | ||
| graph: META_GRAPH, | ||
| contextGraphId: CONTEXT_GRAPH_ID, | ||
| ual: UAL_ONE, | ||
| operation: 'urn:dkg:workspace-operation:first-capture', | ||
| head: { shareOperationId: 'first-capture' }, | ||
| operationShareOperationIds: ['first-capture'], | ||
| })); | ||
| const firstOwner = {}; | ||
| await initializeRfc64LegacySwmBoundaryV1(firstOwner, root, store); | ||
|
|
||
| expect(readRfc64LegacySwmBoundaryCountV1(firstOwner, CONTEXT_GRAPH_ID)).toBe(1); | ||
|
|
||
| // A later restart must load the immutable first-upgrade capture instead of | ||
| // silently classifying a new 10.0.16 share as historical. | ||
| heads.set(SUBGRAPH_META_GRAPH, [UAL_TWO]); | ||
| await store.insert(legacySwmBoundaryFixtureQuadsV1({ | ||
| graph: SUBGRAPH_META_GRAPH, | ||
| contextGraphId: CONTEXT_GRAPH_ID, | ||
| ual: UAL_TWO, | ||
| operation: 'urn:dkg:workspace-operation:late-named', | ||
| head: { shareOperationId: 'late-named' }, | ||
| operationShareOperationIds: ['late-named'], | ||
| })); | ||
| const restartedOwner = {}; | ||
| await initializeRfc64LegacySwmBoundaryV1(restartedOwner, root, store); | ||
| expect(readRfc64LegacySwmBoundaryCountV1(restartedOwner, CONTEXT_GRAPH_ID)).toBe(1); | ||
|
|
@@ -102,7 +114,7 @@ describe('RFC-64 10.0.16 legacy SWM boundary', () => { | |
| const secondRestartOwner = {}; | ||
| await initializeRfc64LegacySwmBoundaryV1(secondRestartOwner, root, store); | ||
| expect(readRfc64LegacySwmBoundaryCountV1(secondRestartOwner, CONTEXT_GRAPH_ID)).toBe(0); | ||
| expect(store.listGraphs).not.toHaveBeenCalled(); | ||
| expect(listGraphs).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('persists an atomic post-capture legacy SHARE companion until that exact UAL is republished', async () => { | ||
|
|
@@ -540,56 +552,33 @@ describe('RFC-64 10.0.16 legacy SWM boundary', () => { | |
| expect(readRfc64LegacySwmBoundaryCountV1(owner, CONTEXT_GRAPH_ID)).toBe(0); | ||
| }); | ||
|
|
||
| it('does not let named metadata graphs consume the root graph capture cap', async () => { | ||
| it('captures the root graph with one behavioral store read and no graph enumeration', async () => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Issue: The rewritten capture test drops the only guard that named subgraph metadata graphs cannot enter the legacy SWM capture What's wrong Example // capture file is written here Expected observation that is now missing: initialize against a fresh persistence root with (i) a root-graph legacy head and (ii) 16_384+ named subgraph Suggested direction Confidence note For Agents |
||
| const root = await secureTempRoot(roots); | ||
| const heads = new Map<string, string[]>([[META_GRAPH, [UAL_ONE]]]); | ||
| for (let index = 0; index < 16_384; index += 1) { | ||
| heads.set( | ||
| contextGraphSharedMemoryMetaUri(CONTEXT_GRAPH_ID, `named-${index}`), | ||
| [], | ||
| ); | ||
| } | ||
| const store = fakeStore(heads); | ||
| const store = new OxigraphStore(); | ||
| await store.insert(legacySwmBoundaryFixtureQuadsV1({ | ||
| graph: META_GRAPH, | ||
| contextGraphId: CONTEXT_GRAPH_ID, | ||
| ual: UAL_ONE, | ||
| operation: 'urn:dkg:workspace-operation:bounded-read', | ||
| head: { shareOperationId: 'bounded-read' }, | ||
| operationShareOperationIds: ['bounded-read'], | ||
| })); | ||
| const listGraphs = vi.spyOn(store, 'listGraphs'); | ||
| const query = vi.spyOn(store, 'query'); | ||
|
|
||
| const owner = {}; | ||
| await initializeRfc64LegacySwmBoundaryV1(owner, root, store); | ||
|
|
||
| expect(readRfc64LegacySwmBoundaryCountV1(owner, CONTEXT_GRAPH_ID)).toBe(1); | ||
| expect(store.listGraphs).not.toHaveBeenCalled(); | ||
| expect(store.query).toHaveBeenCalledWith( | ||
| expect.stringContaining('GRAPH ?metaGraph'), | ||
| expect.objectContaining({ | ||
| source: 'agent.rfc64.legacySwmBoundary.readHeads', | ||
| }), | ||
| ); | ||
| }); | ||
|
|
||
| it('uses one bounded fully correlated capture query', async () => { | ||
| const root = await secureTempRoot(roots); | ||
| const store = fakeStore(new Map([[META_GRAPH, [UAL_ONE]]])); | ||
|
|
||
| await initializeRfc64LegacySwmBoundaryV1({}, root, store); | ||
|
|
||
| const captureQueryCalls = vi.mocked(store.query).mock.calls.filter(([, options]) => ( | ||
| expect(listGraphs).not.toHaveBeenCalled(); | ||
| const captureQueryCalls = query.mock.calls.filter(([, options]) => ( | ||
| options?.source === 'agent.rfc64.legacySwmBoundary.readHeads' | ||
| )); | ||
| expect(captureQueryCalls).toHaveLength(1); | ||
| const captureQuery = captureQueryCalls[0]![0]; | ||
| expect(captureQuery).toContain( | ||
| '?operation <http://www.w3.org/1999/02/22-rdf-syntax-ns#type>', | ||
| ); | ||
| expect(captureQuery).toContain( | ||
| 'BIND(?operationUal AS ?ual)', | ||
| ); | ||
| expect(captureQuery).toContain( | ||
| '?head <http://dkg.io/ontology/kaUal> ?ual ; <http://dkg.io/ontology/shareOperationId> ?shareId', | ||
| ); | ||
| expect(captureQuery).toContain('LIMIT 100001'); | ||
| expect(captureQuery).toContain( | ||
| 'FILTER(STRENDS(STR(?head), "#dkg-swm-head"))', | ||
| ); | ||
| expect(captureQuery).not.toContain('VALUES'); | ||
| expect(captureQuery).not.toContain('queryHints#'); | ||
| // The fail-closed head cap (legacy-swm-boundary-v1.ts: bindings.length > | ||
| // RFC64_LEGACY_SWM_HEAD_LIMIT_V1) is only reachable while the query fetches | ||
| // one row MORE than the limit, so pin that exact relationship. | ||
| expect(captureQueryCalls[0]![0]).toContain('LIMIT 100001'); | ||
| }); | ||
|
|
||
| it.each([ | ||
|
|
@@ -753,29 +742,6 @@ async function secureTempRoot(roots: string[]): Promise<string> { | |
| return root; | ||
| } | ||
|
|
||
| function fakeStore( | ||
| headsByGraph: Map<string, string[]>, | ||
| ): TripleStore { | ||
| return { | ||
| listGraphs: vi.fn(async () => [...headsByGraph.keys()]), | ||
| query: vi.fn(async (_sparql: string, options?: { source?: string }) => { | ||
| const rootHeads = headsByGraph.get(META_GRAPH) ?? []; | ||
| if (options?.source === 'agent.rfc64.legacySwmBoundary.readHeads') { | ||
| return { | ||
| type: 'bindings' as const, | ||
| bindings: rootHeads.map((ual) => ({ | ||
| metaGraph: META_GRAPH, | ||
| head: `${ual}#dkg-swm-head`, | ||
| ual, | ||
| contextGraphId: `"${CONTEXT_GRAPH_ID}"`, | ||
| })), | ||
| }; | ||
| } | ||
| return { type: 'bindings' as const, bindings: [] }; | ||
| }), | ||
| } as unknown as TripleStore; | ||
| } | ||
|
|
||
| function captureBinding( | ||
| contextGraphId = CONTEXT_GRAPH_ID, | ||
| ual = UAL_ONE, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -209,6 +209,53 @@ describe('exact VM recovery lifecycle', () => { | |
| } | ||
| }); | ||
|
|
||
| it.each(['configured-store', 'storeless'] as const)( | ||
| 'awaits strict membership reconciliation and propagates failure with a %s', | ||
| async (storeCase) => { | ||
| const membershipUpsert = vi.fn(async () => undefined); | ||
| const agent = await createAgentWithSend( | ||
| async () => new Uint8Array(0), | ||
| undefined, | ||
| storeCase === 'configured-store' | ||
| ? { | ||
| loadAll: async () => [], | ||
| upsert: membershipUpsert, | ||
| delete: async () => undefined, | ||
| } | ||
| : undefined, | ||
| ); | ||
| const reconciliation = deferred<void>(); | ||
| const reconciliationFailure = new Error('responsibility reconciliation failed'); | ||
| const reconcile = vi.spyOn(agent, 'reconcileRfc64CatalogResponsibilityV1') | ||
| .mockReturnValue(reconciliation.promise); | ||
| try { | ||
| let settled = false; | ||
| const strictWrite = agent.upsertContextGraphMember({ | ||
| contextGraphId: `strict-membership-${storeCase}`, | ||
| principalType: 'node', | ||
| principalId: PEER_A, | ||
| status: 'active', | ||
| }, { strict: true }); | ||
| const failure = strictWrite.then( | ||
| () => { settled = true; return undefined; }, | ||
| (error: unknown) => { settled = true; return error; }, | ||
| ); | ||
|
|
||
| await vi.waitFor(() => expect(reconcile).toHaveBeenCalledOnce()); | ||
| expect(membershipUpsert).toHaveBeenCalledTimes( | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔵 Nit: The storeless branch asserts a never-wired mock was not called, so part of the new test is vacuous Why it matters Suggestion |
||
| storeCase === 'configured-store' ? 1 : 0, | ||
| ); | ||
| expect(settled).toBe(false); | ||
|
|
||
| reconciliation.reject(reconciliationFailure); | ||
| expect(await failure).toBe(reconciliationFailure); | ||
| } finally { | ||
| reconciliation.resolve(); | ||
| await agent.stop().catch(() => {}); | ||
| } | ||
| }, | ||
| ); | ||
|
|
||
| it('quarantines a physically active reconcile until shutdown is retried', async () => { | ||
| const timeoutDescriptor = Object.getOwnPropertyDescriptor( | ||
| DKGAgentBase, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -299,6 +299,53 @@ describe('RPC usage accounting — raw request counts EQUAL the server-received | |
| }); | ||
| }); | ||
|
|
||
| it('gives canonical tracker attribution precedence over its legacy compatibility map', () => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 Bug: The "canonical attribution precedence" test can pass even if normalization ignores What's wrong Example Suggested direction For Agents |
||
| const tracker = new RpcUsageTracker(() => 'evm:31337'); | ||
| withRpcUsageConsumer('token.balanceOf', () => tracker.record('eth_call')); | ||
|
|
||
| const dualFormatWindow = tracker.drainWindow(); | ||
| expect(dualFormatWindow.ethCallByConsumer).toEqual({ 'token.balanceOf': 1 }); | ||
| expect(dualFormatWindow.attributions).toEqual([ | ||
| { method: 'eth_call', consumer: 'token.balanceOf', count: 1 }, | ||
| ]); | ||
| const normalized = normalizeRpcUsageWindow(dualFormatWindow); | ||
| expect(normalized.ethCallByConsumer).toEqual({ 'token.balanceOf': 1 }); | ||
| expect(normalized.attributions).toEqual([ | ||
| { method: 'eth_call', consumer: 'token.balanceOf', count: 1 }, | ||
| ]); | ||
|
|
||
| // A tracker-drained window carries both representations built from the | ||
| // SAME counters, so it can only ever show them agreeing. Precedence is | ||
| // only observable when they disagree — hand-build that case. Reverting | ||
| // normalizeRpcUsageWindow to the legacy branch yields | ||
| // { 'stale.legacy': 9 } here and drops the eth_getLogs attribution. | ||
| const contradictory = normalizeRpcUsageWindow({ | ||
| byMethod: { eth_call: 3, eth_getLogs: 1 }, | ||
| ethCallByConsumer: { 'stale.legacy': 9 }, | ||
| ethGetLogsByConsumerAndEndpointSlot: { 'stale.legacy': { primary: 9 } }, | ||
| attributions: [ | ||
| { method: 'eth_call', consumer: 'token.balanceOf', count: 3 }, | ||
| { | ||
| method: 'eth_getLogs', | ||
| consumer: 'cg.authority.history', | ||
| endpointSlot: 'fallback_1', | ||
| count: 1, | ||
| }, | ||
| ], | ||
| lifetimeTotal: 4, | ||
| }); | ||
| expect(contradictory.ethCallByConsumer).toEqual({ 'token.balanceOf': 3 }); | ||
| expect(contradictory.attributions).toEqual([ | ||
| { method: 'eth_call', consumer: 'token.balanceOf', count: 3 }, | ||
| { | ||
| method: 'eth_getLogs', | ||
| consumer: 'cg.authority.history', | ||
| endpointSlot: 'fallback_1', | ||
| count: 1, | ||
| }, | ||
| ]); | ||
| }); | ||
|
|
||
| it('returns a concrete empty RPC usage window from the mock adapter', () => { | ||
| expect(new MockChainAdapter().drainRpcUsage()).toEqual({ | ||
| byMethod: {}, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔵 Nit: The re-export keeps a second name for the shared
MemoryWorkspaceSnapshotStore.Why it matters
An alias that only exists to avoid updating two import lists adds a naming indirection: readers must chase it to learn which store implementation a test uses, and future callers have no signal about which name is canonical.
Suggestion
Drop the alias (or re-export under the canonical name) and update the two importers (
swm-recovery.test.ts,swm-recovery-revocation.test.ts) so the codebase has one name for the shared helper; folding the remaining local copies into the shared module can follow separately since they are pre-existing.