job-application-agent 3.4.2 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -71,6 +71,11 @@ function submission(index, roundId, overrides = {}) {
71
71
  };
72
72
  }
73
73
 
74
+ function recordLeads(env, roundId, sourceId, entries, otherCount = 0) {
75
+ for (const app of entries) cli(env, ['round','lead','--stdin'], { roundId, sourceId, applicationId: app.id, url: app.url, employerJobId: app.employerJobId, company: app.company, role: app.role, disposition:'qualified', observedAt:app.submittedAt, evidence:'Synthetic role meets the target requirements.' });
76
+ for (let i=0;i<otherCount;i++) cli(env, ['round','lead','--stdin'], { roundId, sourceId, url:`https://other.fixture.example/${sourceId}/${i}`, company:`Other ${i}`, disposition:'no-relevant-opening', observedAt:'2026-08-01T00:00:00Z', evidence:'No target role on this careers page.' });
77
+ }
78
+
74
79
  test('persists a scoped autonomy grant and revokes future routine transmissions', async (t) => {
75
80
  const { directory, env } = await fixture(t, 'autonomy');
76
81
 
@@ -122,6 +127,7 @@ test('counts only unique confirmed ledger submissions for an explicit round', as
122
127
  assert.equal(status.completed, false);
123
128
 
124
129
  for (const sourceId of ['linkedin-jobs-feed', 'indeed', 'hacker-news-who-is-hiring']) {
130
+ recordLeads(env, started.roundId, sourceId, sourceId === 'linkedin-jobs-feed' ? Array.from({ length:30 },(_,i)=>submission(i,started.roundId)) : [], sourceId === 'linkedin-jobs-feed' ? 0 : 30);
125
131
  cli(env, ['round', 'source', '--stdin'], {
126
132
  roundId: started.roundId, sourceId, status: 'searched', reviewedCount: 30, qualifiedCount: sourceId === 'linkedin-jobs-feed' ? 30 : 0,
127
133
  evidence: 'Reviewed matching postings against the unchanged target; other leads did not qualify.',
@@ -142,6 +148,8 @@ test('round completion requires distinct source coverage and explains concentrat
142
148
  const { roundId } = cli(env, ['round', 'start', '--stdin'], { requestedCount: 2 });
143
149
  for (const i of [1, 2]) cli(env, ['ledger', 'add', '--stdin'], submission(i, roundId, { discoverySourceId: 'linkedin-jobs-feed' }));
144
150
  assert.match(cliFailure(env, ['round', 'complete', '--stdin'], { roundId }).stderr, /3 distinct discovery sources/i);
151
+ recordLeads(env,roundId,'linkedin-jobs-feed',[submission(1,roundId),submission(2,roundId)],8);
152
+ recordLeads(env,roundId,'indeed',[],10);
145
153
  const check = { roundId, sourceId: 'linkedin-jobs-feed', status: 'searched', reviewedCount: 10, qualifiedCount: 2, evidence: 'Reviewed ten relevant postings using the target constraints.' };
146
154
  cli(env, ['round', 'source', '--stdin'], check);
147
155
  cli(env, ['round', 'source', '--stdin'], check);
@@ -169,7 +177,10 @@ test('discovery coverage rejects invalid reports and requires attribution withou
169
177
  for (const bad of [{ sourceId: 'imaginary-board' }, { qualifiedCount: 5 }, { status: 'blocked' }, { applicationIds: ['not-in-round'] }, { evidence: '' }, { privateProfile: 'forbidden' }]) {
170
178
  assert.equal(cliFailure(env, ['round', 'source', '--stdin'], { ...check, ...bad }).status, 1);
171
179
  }
172
- for (const sourceId of ['linkedin-jobs-feed', 'indeed', 'hacker-news-who-is-hiring']) cli(env, ['round', 'source', '--stdin'], { ...check, sourceId });
180
+ for (const sourceId of ['linkedin-jobs-feed', 'indeed', 'hacker-news-who-is-hiring']) {
181
+ recordLeads(env,roundId,sourceId,[submission(1,roundId)],3);
182
+ cli(env, ['round', 'source', '--stdin'], { ...check, sourceId });
183
+ }
173
184
  assert.match(cliFailure(env, ['round', 'complete', '--stdin'], { roundId }).stderr, /attribution/i);
174
185
  cli(env, ['round', 'source', '--stdin'], { ...check, applicationIds: ['round-role-1'] });
175
186
  assert.equal(cli(env, ['round', 'status', roundId]).discovery.unattributedCount, 0);
@@ -180,7 +191,11 @@ test('source diversity is independent of ATS and concentration explanations are
180
191
  const { env } = await fixture(t, 'balanced-discovery');
181
192
  const { roundId } = cli(env, ['round', 'start', '--stdin'], { requestedCount: 5 });
182
193
  const ids = ['linkedin-jobs-feed', 'indeed', 'hacker-news-who-is-hiring'];
183
- for (const sourceId of ids) cli(env, ['round', 'source', '--stdin'], { roundId, sourceId, status: 'searched', reviewedCount: 3, qualifiedCount: 2, evidence: 'Reviewed relevant postings and verified target fit.' });
194
+ for (const sourceId of ids) {
195
+ const entries=Array.from({length:5},(_,i)=>submission(i+1,roundId)).filter((_,i)=>ids[i%3]===sourceId);
196
+ recordLeads(env,roundId,sourceId,entries,1);
197
+ cli(env, ['round', 'source', '--stdin'], { roundId, sourceId, status: 'searched', evidence: 'Reviewed relevant postings and verified target fit.' });
198
+ }
184
199
  for (let i = 1; i <= 5; i++) cli(env, ['ledger', 'add', '--stdin'], submission(i, roundId, { discoverySourceId: ids[(i - 1) % 3], applicationChannel: 'ashby' }));
185
200
  const completed = cli(env, ['round', 'complete', '--stdin'], { roundId });
186
201
  assert.equal(completed.discovery.maxSourceSharePercent, 40);
@@ -197,6 +212,7 @@ test('blocked-only attempts and two views of the same network do not satisfy dis
197
212
  cli(env, ['round', 'source', '--stdin'], { ...check, sourceId: 'indeed' });
198
213
  assert.equal(cli(env, ['round', 'status', roundId]).discovery.coverageSatisfied, false);
199
214
  const { blocker, ...searched } = check;
215
+ recordLeads(env,roundId,'indeed',[submission(1,roundId)]);
200
216
  cli(env, ['round', 'source', '--stdin'], { ...searched, sourceId: 'indeed', status: 'searched', reviewedCount: 1, qualifiedCount: 1 });
201
217
  cli(env, ['round', 'source', '--stdin'], { ...check, sourceId: 'indeed' });
202
218
  assert.equal(cli(env, ['round', 'status', roundId]).discovery.coverageSatisfied, true);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "job-application-agent",
3
- "version": "3.4.2",
3
+ "version": "3.5.0",
4
4
  "description": "A privacy-first Agent Skill and CLI for evidence-based job discovery, application completion, and outcome tracking.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -44,7 +44,7 @@
44
44
  "check:native-artifacts": "node scripts/ci/validate-native-artifacts.mjs",
45
45
  "privacy-audit": "node --test job-application-agent/tests/privacy-audit.test.mjs",
46
46
  "smoke:package": "node scripts/smoke-package.mjs",
47
- "check": "node --check job-application-agent/scripts/job-application.mjs && node --check job-application-agent/scripts/cloud-state-client.mjs && node --check job-application-agent/scripts/secret-store.mjs && node --check job-application-agent/scripts/source-community-client.mjs && node --check job-application-agent/scripts/source-community-schema.mjs && node --check job-application-agent/scripts/telemetry-client.mjs && node --check job-application-agent/scripts/telemetry-schema.mjs && node --check job-application-agent/scripts/version.mjs && node --check telemetry-worker/src/worker.mjs && node --check telemetry-worker/src/public-stats.mjs && node --check telemetry-worker/public/dashboard.js && node --check installer/src/cli.mjs && node --check installer/src/installer.mjs && node --check installer/src/runner.mjs && node --check installer/src/scheduler.mjs && node --check scripts/ci/classify-paths.mjs && node --check scripts/ci/validate-native-artifacts.mjs && node --check bin/job-application-agent.mjs && node --check state-worker/src/worker.mjs && node --check state-worker/src/backup.mjs && node --check state-worker/src/cli.mjs && node --check state-worker/bin/sync.mjs",
47
+ "check": "node --check job-application-agent/scripts/job-application.mjs && node --check job-application-agent/scripts/cloud-state-client.mjs && node --check job-application-agent/scripts/secret-store.mjs && node --check job-application-agent/scripts/source-community-client.mjs && node --check job-application-agent/scripts/source-community-schema.mjs && node --check job-application-agent/scripts/telemetry-client.mjs && node --check job-application-agent/scripts/telemetry-schema.mjs && node --check job-application-agent/scripts/version.mjs && node --check telemetry-worker/src/worker.mjs && node --check telemetry-worker/src/public-stats.mjs && node --check telemetry-worker/public/dashboard.js && node --check installer/src/cli.mjs && node --check installer/src/installer.mjs && node --check installer/src/runner.mjs && node --check installer/src/scheduler.mjs && node --check scripts/ci/classify-paths.mjs && node --check scripts/ci/validate-native-artifacts.mjs && node --check bin/job-application-agent.mjs && node --check state-worker/src/worker.mjs && node --check state-worker/src/backup.mjs && node --check state-worker/src/cli.mjs && node --check state-worker/bin/sync.mjs && node --check job-application-agent/scripts/application-accounting.mjs",
48
48
  "prepack": "npm run check && npm test && npm run privacy-audit"
49
49
  },
50
50
  "engines": {