refactor: shared agent workflows (F01) and one application registry (F02)
Checkpoint for the 2026-09-11 project review remediation. Work by a previous agent that ran out of context; committed unchanged as a rollback point before the remaining findings land on top of it. F01 — the two agent directories had drifted into different processes - Six shared workflows under `resume_builder/reference/workflows/`; both `.agents/skills/` and `.claude/skills/` are now thin entrypoints that route to the same file instead of carrying full copies. - The `.claude` copies were the stale side: fixed bullet line variants and character budgets that the newer process had already dropped. Removing them is the point of the change, not collateral. - Parity/link regression test added; corrected the top-level file map, which pointed at a directory that does not exist. F02 — application status was stored in four places and disagreed - New registry `job_scout/state/applications.json` (26 records) with `application_records.py` (schema, validation, transactional write) and `application_tracker.py` (add/update, no quota). - AGENTS.md and CLAUDE.md no longer keep their own status tables; both point at `current_applications.md`, generated from the registry. - Interview-reached is now independent of outcome, so a withdrawal after an interview can record both facts. The old tables are preserved verbatim in `job_scout/state/history/application_status_before_2026-09-11.json`. Verification: `python -m unittest discover -s tests -v` — 18/18 pass. Spot-checked that the detailed SBB and Kdo Cy notes survived the migration into the registry rather than being flattened. Known unresolved, deliberately not invented (see FIX_PROGRESS.md): Aker BP's application date and its Adjacent-despite-79 classification. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Qej5SBvhcbGXHwLqNWiskM
This commit is contained in:
1 parent
0d999ab21b
commit
afdef7eb94
33 files changed
+1558
-1768
No files matched your search
@@ -1,81 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Record and summarize the controlled ten-application cohort."""
|
||||
"""Compatibility entry point; application_tracker owns the uncapped registry workflow."""
|
||||
from application_tracker import main
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
TRACKER = ROOT / "job_scout" / "state" / "application_cohort.json"
|
||||
FIT_CLASSES = ("core", "adjacent", "stretch")
|
||||
CHANNELS = ("strong", "moderate", "weak")
|
||||
|
||||
|
||||
def load() -> dict:
|
||||
return json.loads(TRACKER.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def save(data: dict) -> None:
|
||||
TRACKER.write_text(json.dumps(data, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
||||
|
||||
|
||||
def summary(data: dict) -> None:
|
||||
applications = data["applications"]
|
||||
# Slot caps were dropped 2026-09-05 (application_strategy.md). This is a record, not a
|
||||
# budget: report counts, never counts-against-a-target, so nothing reads as a remaining slot.
|
||||
print(f"Application record: {data['cohort_id']} ({len(applications)} applications)")
|
||||
for fit_class in FIT_CLASSES:
|
||||
count = sum(item["fit_class"] == fit_class for item in applications)
|
||||
print(f" {fit_class}: {count}")
|
||||
for channel in CHANNELS:
|
||||
count = sum(item["channel"] == channel for item in applications)
|
||||
print(f" channel {channel}: {count}")
|
||||
outcomes: dict[str, int] = {}
|
||||
for item in applications:
|
||||
outcome = item.get("outcome", "open")
|
||||
outcomes[outcome] = outcomes.get(outcome, 0) + 1
|
||||
print(" outcomes: " + ", ".join(f"{key}={value}" for key, value in sorted(outcomes.items())))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
subparsers = parser.add_subparsers(dest="command", required=True)
|
||||
subparsers.add_parser("summary")
|
||||
add = subparsers.add_parser("add")
|
||||
add.add_argument("--company", required=True)
|
||||
add.add_argument("--role", required=True)
|
||||
add.add_argument("--date", required=True)
|
||||
add.add_argument("--fit-class", choices=FIT_CLASSES, required=True)
|
||||
add.add_argument("--evidence-fit", type=float, required=True)
|
||||
add.add_argument("--channel", choices=CHANNELS, required=True)
|
||||
add.add_argument("--hard-gate", choices=("pass", "fail"), required=True)
|
||||
add.add_argument("--outcome", default="open")
|
||||
|
||||
args = parser.parse_args()
|
||||
data = load()
|
||||
if args.command == "add":
|
||||
if len(data["applications"]) >= 10:
|
||||
raise SystemExit("cohort already contains ten applications")
|
||||
if args.hard_gate == "fail" and args.fit_class != "stretch":
|
||||
raise SystemExit("a hard-gate failure must be recorded as stretch")
|
||||
data["applications"].append(
|
||||
{
|
||||
"company": args.company,
|
||||
"role": args.role,
|
||||
"application_date": args.date,
|
||||
"fit_class": args.fit_class,
|
||||
"evidence_fit": args.evidence_fit,
|
||||
"hard_gate": args.hard_gate,
|
||||
"channel": args.channel,
|
||||
"outcome": args.outcome,
|
||||
}
|
||||
)
|
||||
save(data)
|
||||
summary(data)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in new issue
Block a user