ThatAIguyA world of ideas

THE CONSCIOUSNESS ATLAS
Read. Experiment. Follow the evidence.

ConsciousnessLearn · Explore · Joseph Anady

Janady13/missionmatch / internal/modules/ontology/adapters/onet.go

Source identity, revision, and recovered contents.

GitHub sourceSource text recovered

Source identity

FieldRecorded value
Source typeGitHub source
Original recordJanady13/missionmatch / internal/modules/ontology/adapters/onet.go
DateNot specified in source
RepositoryJanady13/missionmatch
Revision720d47fae476b0d38477ae4401697d372b1ea2bc
Branchfeature/opportunity-to-outcome
Path or archive memberinternal/modules/ontology/adapters/onet.go
Original SHA-2560e864cbc103dc108d3518a532e2df3f8828389cb0e0fb2b9eca6851cbaeafa5a
Git blob SHA65fb41568eee65c3f3cacd4bd2043da035159db7
Reading-copy SHA-256fea5efa50c4270190453c9d1e257b512988d3bc091679e7e09b63e9580750507

Original source ↗

Every recorded occurrence

These 20 records contain identical original source bytes. Their paths and revisions remain part of the archive.

Original recordBranch or archiveRevision / identifierOriginal location
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gofeature/opportunity-to-outcome720d47fae476b0d38477ae4401697d372b1ea2bcOpen original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gocollision-deconfliction4ee5a09972608ed89f8377c6665542d5f450f0a6Open original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gows6-retrieval6c56e29231ec05735927fa265c97d517499dfeafOpen original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gom5-price-to-win41000ad30fff4129fdaf5ec84e15ba14c27d4890Open original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gows1-ontology-syncb596f449a32a1016fbd403c36505cc00a1ac9ee6Open original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gomaster1e9249840a4302ec82e123b9c9cb6f75badea3e4Open original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gows8-teaching-loopc823f0fb6bb2aba0f39001eb6de96f4000d9321fOpen original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gomag-substrateb82c7100a492dec67dfd1eda6b3f53def859be35Open original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gows3-clearance4b8e7ce594c068621867f9c9deed0ec64ae6c553Open original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gophase2-eval-fairnessd361af254701975fe239927656ababb56374655eOpen original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gotime-to-fill-survivalb66e1e505863d4f17741a4b9ede73509e45bd6c6Open original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gographrag-foundationb0ddeb9f633fd138d09309d1a17b7d13bc3a67f7Open original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gows9-bench-ingestionf585a9ef32fa554663ce1fba9a414a54b6e49cf0Open original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gows2-alias-relationshipe4dada4601c6eb101830f9d223a9655dfa120616Open original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gopresentation-readinesseb574acaa29d71ce4d0f852572e87c275c79fdb7Open original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.govendor-intelligencefe9796a19c261951d3f2565206c0c1b5ac294465Open original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gows7-federal-signal6a9f6ce9cfb13345ffb47770d4960e7c2d9c17c2Open original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gophase2-connectorse038d4c687aec16f8bd9bc4d907eea14d91f8704Open original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gofeature/aioe-upgrade2178e7298d0e5d9af83afa12402fd587f0ba6ed8Open original
Janady13/missionmatch / internal/modules/ontology/adapters/onet.gocapture-readinessbae6af7cb2997e819174a9e9cfff5e16067a1975Open original

Recovered source transcript

Credential-bearing and unrelated personal details were removed from this reading copy. The source identity and original checksum remain recorded.

package adapters import ( "context" "encoding/json" "fmt" "io" "log" "net/http" "strings" "time" "github.com/missionworkforce/missionmatch/internal/modules/ontology" ) // ONETAttribution is the required attribution string for O*NET Web Services content. // O*NET Web Services requires this notice on any product using their data. // The exact text must be reproduced verbatim including its internal punctuation. const ONETAttribution = "O*NET Web Services by the U.S. Department of Labor, Employment and Training Administration (USDOL/ETA). Used under the CC BY 4.0 license. O*NET is a trademark of USDOL/ETA." // onetBaseURL is the O*NET Web Services v2.0 base URL. It is the default used by NewONETSource // and can be overridden for tests by setting the baseURL field directly after construction. const onetBaseURL = "https://api-v2.onetcenter.org" // onetMaxRetries is the bounded number of retry attempts on a 429 response before giving up // and returning ontology.ErrThrottled. const onetMaxRetries = 3 // onetRetryDelay is the back off duration applied between 429 retry attempts (about 200ms). const onetRetryDelay = 200 * time.Millisecond // onetMinInterval is the minimum time between requests, enforcing a ceiling of 5 requests // per second without requiring an external dependency. const onetMinInterval = 200 * time.Millisecond // ONETSource ingests the O*NET Web Services v2.0 occupation skills, knowledge, abilities, and // technology skills into the ontology store. Skills are yielded as KindSkill records; knowledge // and abilities are yielded as KindKSA records; technology skills (concrete software tools) are // yielded as KindSkill records. Each element kind is globally deduped: a skill element such as // Active Listening appears once no matter how many occupations list it, and a technology tool // such as Apache Kafka appears once regardless of how many occupations reference it. // // This adapter is DORMANT until an ONET_API_KEY is [credential removed] The CLI constructs it only when // the key is present. The unit tests cover the pure parser functions only and do not call the // live API. // // Attribution: this adapter incorporates information from O*NET Web Services by the U.S. // Department of Labor (see ONETAttribution for the full required notice). type ONETSource struct { apiKey string baseURL string client *http.Client lastCall time.Time } // NewONETSource builds the adapter. apiKey is the O*NET developer key; it is sent only in the // X-API-Key request header, never in the query string or body. client is the HTTP client; pass // nil for a sensible 30 second default. The base URL defaults to the O*NET v2.0 production // endpoint and can be overridden by setting the baseURL field after construction. func NewONETSource(apiKey string, client *http.Client) *ONETSource { if client == nil { client = &http.Client{Timeout: 30 * time.Second} } return &ONETSource{ apiKey: [credential removed], baseURL: onetBaseURL, client: client, } } // Name is the provenance label stamped on every record this source yields. func (s *ONETSource) Name() string { return "O*NET Web Services" } // Fetch lists all O*NET occupations, then for each occupation pulls skills, knowledge, abilities, // and technology skills, yielding one VocabRecord per distinct element. A global seen map ensures // each unique SourceRecordID is yielded exactly once: generic competencies (skills, knowledge, // abilities) and technology tools that appear across many occupations are stored as one row, not // one row per occupation. Requests are throttled to about 5 per second. A 429 that cannot be // recovered within onetMaxRetries attempts returns ontology.ErrThrottled. // // This method incorporates information from O*NET Web Services by the U.S. Department of Labor. func (s *ONETSource) Fetch(ctx context.Context, yield func(ontology.VocabRecord) error) error { log.Print("onet: fetch started, incorporates information from O*NET Web Services by the U.S. Department of Labor") codes, err := s.listOccupations(ctx) if err != nil { return fmt.Errorf("onet: list occupations: %w", err) } type elementSpec struct { path string category string kind ontology.TermKind isTech bool } specs := []elementSpec{ {path: "skills", category: "skill", kind: ontology.KindSkill}, {path: "knowledge", category: "knowledge", kind: ontology.KindKSA}, {path: "abilities", category: "ability", kind: ontology.KindKSA}, {path: "technology_skills", kind: ontology.KindSkill, isTech: true}, } // seen tracks SourceRecordIDs that have already been yielded. Any record whose key appears // in seen is skipped so the store receives one upsert per distinct competency or tool, not // one per occupation that mentions it (roughly 1016 repetitions for common elements). seen := make(map[string]bool) for _, code := range codes { for _, spec := range specs { url := fmt.Sprintf("%s/online/occupations/%s/summary/%s", s.baseURL, code, spec.path) data, err := s.getWithRetry(ctx, url) if err != nil { return fmt.Errorf("onet: occupation %s %s: %w", code, spec.path, err) } var recs []ontology.VocabRecord if spec.isTech { recs, err = parseONETTechSkills(data, code) } else { recs, err = parseONETElement(data, code, spec.category, spec.kind) } if err != nil { return fmt.Errorf("onet: parse occupation %s %s: %w", code, spec.path, err) } for _, r := range recs { if seen[r.SourceRecordID] { continue } seen[r.SourceRecordID] = true if err := yield(r); err != nil { return err } } } } return nil } // listOccupations fetches all pages of /online/occupations/ and returns the O*NET SOC codes. func (s *ONETSource) listOccupations(ctx context.Context) ([]string, error) { var codes []string start := 1 for { url := fmt.Sprintf("%s/online/occupations/?start=%d&end=%d", s.baseURL, start, start+99) data, err := s.getWithRetry(ctx, url) if err != nil { return nil, err } page, err := parseONETOccupations(data) if err != nil { return nil, err } if len(page) == 0 { break } codes = append(codes, page...) var pag onetPagination if err := json.Unmarshal(data, &pag); err != nil { return nil, fmt.Errorf("onet: decode pagination: %w", err) } if pag.Next == "" || pag.End >= pag.Total { break } start = pag.End + 1 } return codes, nil } // throttle enforces a minimum interval between requests (about 5 per second) using a simple // time.Since check and time.Sleep. No external package is needed. It respects ctx cancellation. func (s *ONETSource) throttle(ctx context.Context) error { elapsed := time.Since(s.lastCall) if elapsed < onetMinInterval { wait := onetMinInterval - elapsed select { case <-ctx.Done(): return ctx.Err() case <-time.After(wait): } } s.lastCall = time.Now() return nil } // getWithRetry performs a GET with the X-API-Key header, respects the rate limiter, and retries // up to onetMaxRetries times on a 429 response. If still throttled after all retries it returns // ontology.ErrThrottled. func (s *ONETSource) getWithRetry(ctx context.Context, url string) ([]byte, error) { var lastStatus int for attempt := 0; attempt <= onetMaxRetries; attempt++ { if attempt > 0 { select { case <-ctx.Done(): return nil, ctx.Err() case <-time.After(onetRetryDelay): } } if err := s.throttle(ctx); err != nil { return nil, fmt.Errorf("onet: throttle: %w", err) } data, status, err := s.get(ctx, url) if err != nil { return nil, err } if status == http.StatusTooManyRequests { lastStatus = status continue } if status != http.StatusOK { return nil, fmt.Errorf("onet: provider returned status %d for %s", status, url) } return data, nil } if lastStatus == http.StatusTooManyRequests { return nil, ontology.ErrThrottled } return nil, fmt.Errorf("onet: exhausted retries for %s", url) } // get performs one HTTP GET with the X-API-Key header. The key is sent ONLY in the header, // never in the query string or body, as required by the O*NET Web Services terms of service. func (s *ONETSource) get(ctx context.Context, url string) ([]byte, int, error) { req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return nil, 0, fmt.Errorf("onet: new request: %w", err) } req.Header.Set("X-API-Key", s.apiKey) resp, err := s.client.Do(req) if err != nil { return nil, 0, fmt.Errorf("onet: do request: %w", err) } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { return nil, resp.StatusCode, fmt.Errorf("onet: read body: %w", err) } return body, resp.StatusCode, nil } // onetPagination holds the pagination envelope shared across O*NET v2.0 list responses. type onetPagination struct { Start int `json:"start"` End int `json:"end"` Total int `json:"total"` Next string `json:"next"` } // onetOccupationsResponse mirrors the O*NET v2.0 occupations list response: // // GET /online/occupations/ // { occupation: [{ code, title, href, ... }], start, end, total, next } // // Confirmed from https://services.onetcenter.org/reference/online/browse/occupations. type onetOccupationsResponse struct { onetPagination Occupation []struct { Code string `json:"code"` Title string `json:"title"` } `json:"occupation"` } // parseONETOccupations decodes an O*NET occupations list response and returns the SOC codes. // It is pure (no I/O) so it is directly unit testable. func parseONETOccupations(data []byte) ([]string, error) { var doc onetOccupationsResponse if err := json.Unmarshal(data, &doc); err != nil { return nil, fmt.Errorf("onet: decode occupations: %w", err) } codes := make([]string, 0, len(doc.Occupation)) for _, occ := range doc.Occupation { c := strings.TrimSpace(occ.Code) if c != "" { codes = append(codes, c) } } return codes, nil } // onetElementResponse mirrors the O*NET v2.0 per occupation skills, knowledge, and abilities // summary response shape: // // GET /online/occupations/{code}/summary/{skills|knowledge|abilities} // { element: [{ id, name, description, related }], start, end, total, next } // // Confirmed from https://services.onetcenter.org/reference/online/occupation/summary/skills, // https://services.onetcenter.org/reference/online/occupation/summary/knowledge, and // https://services.onetcenter.org/reference/online/occupation/summary/abilities. // The "id" field is the O*NET content model element id (e.g. "2.A.1.b" for Active Listening). // The "name" field is the human readable element name. type onetElementResponse struct { onetPagination Element []struct { ID string `json:"id"` Name string `json:"name"` Description string `json:"description"` } `json:"element"` } // parseONETElement decodes a per occupation skills, knowledge, or abilities response and returns // one VocabRecord per element. SourceRecordID uses the global "onet:<elementID>" scheme so the // same competency from different occupations carries the same key, enabling dedup in Fetch via the // seen map. category is the element type label ("skill", "knowledge", "ability"). kind is the // TermKind to stamp on each record. It is pure (no I/O) so it is directly unit testable. func parseONETElement(data []byte, socCode, category string, kind ontology.TermKind) ([]ontology.VocabRecord, error) { var doc onetElementResponse if err := json.Unmarshal(data, &doc); err != nil { return nil, fmt.Errorf("onet: decode %s elements: %w", category, err) } out := make([]ontology.VocabRecord, 0, len(doc.Element)) for _, el := range doc.Element { id := strings.TrimSpace(el.ID) name := strings.TrimSpace(el.Name) if id == "" || name == "" { continue } raw, _ := json.Marshal(map[string]string{ "soc_code": socCode, "element_id": id, "name": name, "description": el.Description, "category": category, }) out = append(out, ontology.VocabRecord{ SourceName: "O*NET Web Services", SourceRecordID: "onet:" + id, Kind: kind, Term: name, Code: id, Category: category, Description: strings.TrimSpace(el.Description), Raw: raw, }) } return out, nil } // onetTechSkillsResponse mirrors the O*NET v2.0 per occupation technology_skills summary response: // // GET /online/occupations/{code}/summary/technology_skills // { start, end, total, next, category: [{ code, title, example: [{ title, hot_technology }] }] } // // Confirmed from https://services.onetcenter.org/reference/online/occupation/summary/technology_skills. // Each category groups a class of software tools; each example is a concrete product title. // The response paginates via the shared "next" / "end" / "total" envelope. type onetTechSkillsResponse struct { onetPagination Category []struct { Code int `json:"code"` Title string `json:"title"` Example []struct { Title string `json:"title"` HotTechnology bool `json:"hot_technology"` } `json:"example"` } `json:"category"` } // parseONETTechSkills decodes a per occupation technology_skills response and returns one KindSkill // VocabRecord per example title. SourceRecordID uses "onet-tech:" plus the lowercased, trimmed // example title so the same tool (e.g. "Apache Kafka") from different occupations carries the same // key and is deduped by the seen map in Fetch. Category is set to the tool category title (e.g. // "Development environment software"). Code is empty (tech skills have no O*NET content model id). // Raw is a compact JSON object carrying the SOC code, category title, and tool title. // It is pure (no I/O) so it is directly unit testable. func parseONETTechSkills(data []byte, socCode string) ([]ontology.VocabRecord, error) { var doc onetTechSkillsResponse if err := json.Unmarshal(data, &doc); err != nil { return nil, fmt.Errorf("onet: decode technology_skills: %w", err) } var out []ontology.VocabRecord for _, cat := range doc.Category { catTitle := strings.TrimSpace(cat.Title) for _, ex := range cat.Example { title := strings.TrimSpace(ex.Title) if title == "" { continue } key := "onet-tech:" + strings.ToLower(title) raw, _ := json.Marshal(map[string]string{ "soc_code": socCode, "category": catTitle, "title": title, }) out = append(out, ontology.VocabRecord{ SourceName: "O*NET Web Services", SourceRecordID: key, Kind: ontology.KindSkill, Term: title, Code: "", Category: catTitle, Description: "", Raw: raw, }) } } return out, nil }

Search equations, builds, manuscript text, and recovered sources.